What is the difference between using ConfigureAwait (false) and Task.Run?

I understand that he recommended using ConfigureAwait(false) for await in the library code so that subsequent code does not execute in the context of the caller's execution, which may be a user interface thread. I also understand that await Task.Run(CpuBoundWork) should be used instead of CpuBoundWork() for the same reason.

ConfigureAwait example

 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 the two approaches?

+54
c # async-await
Feb 16
source share
4 answers

When you say Task.Run , you say that you have work with the CPU, it can take a lot of time, so you should always run it in the thread pool thread.

When you say ConfigureAwait(false) , you say that the rest of this async method does not need the original context. ConfigureAwait is more likely a hint of optimization; this does not always mean that the continuation is in the thread pool thread.

+65
Feb 16 '13 at 3:07
source share
— -

In this case, your version of Task.Run will have a bit more overhead since the first wait call ( await client.GetAsync(address) ) will still return to the calling context, as well as the results of calling Task.Run .

In the first example, on the other hand, your first Async() method is configured so that it does not require marshaling back to the calling context, which allows you to continue execution in the background thread. Thus, there will be no marshaling back to the caller context.

+16
Feb 16 '13 at 2:10
source share

Agreed @Stephen's answer, If there is still confusion, see screenshots below 1 # Without ConfigureAwait (false)
See below image. The main topic is trying to update Label. enter image description here

2 # With ConfigureAwait (false)
See below image workflow trying to update shortcut enter image description here

+2
May 07 '17 at 5:03 a.m.
source share

As a side note in both cases, LoadPage() could still block your UI thread, because await client.GetAsync(address) takes time to create a task to go to ConfigureAwait(false) . And your time-consuming operation may have already begun before the task returns.

One possible solution is to use the SynchronizationContextRemover from here :

 public async Task<HtmlDocument> LoadPage(Uri address) { await new SynchronizationContextRemover(); using (var client = new HttpClient()) using (var httpResponse = await client.GetAsync(address)) using (var responseContent = httpResponse.Content) using (var contentStream = await responseContent.ReadAsStreamAsync()) return LoadHtmlDocument(contentStream); //CPU-bound } 
+1
Mar 24 '17 at 10:51
source share



All Articles