Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Async-await Task.Run vs HttpClient.GetAsync

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?

like image 220
vondip Avatar asked Nov 23 '12 22:11

vondip


People also ask

What is the difference between task run and async await?

Async methods are intended to be non-blocking operations. An await expression in an async method doesn't block the current thread while the awaited task is running. Instead, the expression signs up the rest of the method as a continuation and returns control to the caller of the async method.

What is HttpClient GetAsync?

GetAsync(Uri, HttpCompletionOption) Send a GET request to the specified Uri with an HTTP completion option as an asynchronous operation. GetAsync(Uri, CancellationToken) Send a GET request to the specified Uri with a cancellation token as an asynchronous operation.

What does HttpClient GetAsync return?

The HTTP request is sent out, and HttpClient. GetAsync returns an uncompleted Task .

Does async await improve performance?

C# Language Async-Await Async/await will only improve performance if it allows the machine to do additional work.


2 Answers

For server applications, async is about minimizing the number of blocked threads you've got: increasing the efficiency of the thread pool and perhaps allowing your program to scale to more users.

For client applications where you're unlikely to need to care about thread count, async provides a relatively easy way to keep your UI running fluid when you perform I/O.

It is much different from Task.Run underneath the hood.

like image 25
Cory Nelson Avatar answered Oct 13 '22 15:10

Cory Nelson


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;
        }
    }
}
like image 159
Jon Skeet Avatar answered Oct 13 '22 16:10

Jon Skeet