I'm new to c# 5's async feature. I'm trying to understand the difference between these two implementations:
Implementation 1:
private void Start()
{
foreach(var url in urls)
{
ParseHtml(url);
}
}
private async void ParseHtml(string url)
{
var query = BuildQuery(url); //BuildQuery is some helper method
var html = await DownloadHtml(query);
//...
MyType parsedItem = ParseHtml(html);
SaveTypeToDB(parsedItem);
}
private async Task<string> DownloadHtml(string query)
{
using (var client = new HttpClient())
try
{
var response = await client.GetAsync(query);
return (await response.Content.ReadAsAsync<string>());
}
catch (Exception ex)
{
Logger.Error(msg, ex);
return null;
}
}
Implementation 2:
private void DoLoop()
{
foreach(var url in urls)
{
Start(url);
}
}
private async void Start(url)
{
await Task.Run( () => ParseHtml(url)) ;
}
private void ParseHtml(string url)
{
var query = BuildQuery(url); //BuildQuery is some helper method
var html = DownloadHtml(query);
//...
MyType parsedItem = ParseHtml(html);
SaveTypeToDB(parsedItem);
}
private string DownloadHtml(string query)
{
using (var client = new WebClient())
{
try
{
return client.DownloadString(query);
}
catch (Exception ex)
{
Logger.Error(msg, ex);
return null;
}
}
}
I'd rather use the second implementation as it will require less 'async' signatures on methods in my code. I'm trying to understand what's the benefit of using the HttpClient class vs using a new Task and awaiting it instead?
Is there any difference between the two implementations?
I'd rather use the second implementation as it will require less 'async' signatures on methods in my code.
That sounds like a very odd justification. You're trying to execute fundamentally "somewhat asynchronously" - so why not make that clear?
Is there any difference between the two implementations?
Absolutely. The second implementation will tie up a thread while WebClient.DownloadString
blocks, waiting for the request to complete. The first version doesn't have any blocked threads - it relies on a continuation to fire when the request finishes.
Additionally, consider your Logger.Error
call. In the async version, that will still execute in the context of the original calling code. So if this is in, say, a Windows Forms UI, you'll still be on the UI thread, and you can access UI elements etc. In the second version, you'll be executing in a thread pool thread, and would need to marshal back to the UI thread to update the UI.
Note that your async void
method almost certainly shouldn't be async void
. You should only make an async
method return void
for the sake of complying with event handler signatures. In all other cases, return Task
- that way the caller can see when your task has finished, handle exceptions etc.
Also note that you don't need to use HttpClient
for asynchrony - you could use WebClient.DownloadStringTaskAsync
instead, so your final method could become:
private async Task<string> DownloadHtmlAsync(string query)
{
using (var client = new WebClient())
{
try
{
return await client.DownloadStringTaskAsync(query);
}
catch (Exception ex)
{
Logger.Error(msg, ex);
return null;
}
}
}