What are the differences between using ConfigureAwait(false) and Task.Run?

Sam picture Sam · Feb 16, 2013 · Viewed 32.5k times · Source

I understand that it's recommended to use ConfigureAwait(false) for awaits in library code so that subsequent code does not run in the caller's execution context, which could be a UI thread. I also understand that await Task.Run(CpuBoundWork) should be used instead of CpuBoundWork() for the same reason.

Example with ConfigureAwait

public async Task<HtmlDocument> LoadPage(Uri address)
{
    using (var client = new HttpClient())
    using (var httpResponse = await client.GetAsync(address).ConfigureAwait(false))
    using (var responseContent = httpResponse.Content)
    using (var contentStream = await responseContent.ReadAsStreamAsync().ConfigureAwait(false))
        return LoadHtmlDocument(contentStream); //CPU-bound
}

Example with Task.Run

public async Task<HtmlDocument> LoadPage(Uri address)
{
    using (var client = new HttpClient())
    using (var httpResponse = await client.GetAsync(address))
        return await Task.Run(async () =>
        {
            using (var responseContent = httpResponse.Content)
            using (var contentStream = await responseContent.ReadAsStreamAsync())
                return LoadHtmlDocument(contentStream); //CPU-bound
        });
}

What are the differences between these two approaches?

Answer

Stephen Cleary picture Stephen Cleary · Feb 16, 2013

When you say Task.Run, you are saying that you have some CPU work to do that may take a long time, so it should always be run on a thread pool thread.

When you say ConfigureAwait(false), you are saying that the rest of that async method does not need the original context. ConfigureAwait is more of an optimization hint; it does not always mean that the continuation is run on a thread pool thread.