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

后端 未结 4 1942
感动是毒
感动是毒 2020-12-22 22:53

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 e

相关标签:
4条回答
  • 2020-12-22 23:05

    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.

    0 讨论(0)
  • 2020-12-22 23:06

    Agreed @Stephen answer, If still confusion see below screenshots 1# Without ConfigureAwait(false)
    See below image Main thread trying to update Label

    2# With ConfigureAwait(false)
    See below image working thread trying to update label

    0 讨论(0)
  • 2020-12-22 23:06

    As a side note, in both cases LoadPage() could still block your UI thread, because await client.GetAsync(address) needs time to create a task to pass to ConfigureAwait(false). And your time consuming operation might have already started before task is returned.

    One possible solution is to use 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
    }
    
    0 讨论(0)
  • 2020-12-22 23:20

    In this case, your Task.Run version will have a bit more overhead, as the first await call (await client.GetAsync(address)) will still marshal back into the calling context, as will the results of the Task.Run call.

    In the first example, on the other hand, your first Async() method is configured to not require marshaling back into the calling context, which allows the continuation to run on a background thread still. As such, there won't be any marshaling back into the caller's context.

    0 讨论(0)
提交回复
热议问题