Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
642 views
in Technique[技术] by (71.8m points)

.net - C# async/await chaining with ConfigureAwait(false)

Based on numerous books and blogs including this excellent one here, it is clear that when one writes a dll library exposing helper async methods i.e. the wrapper methods, it is generally considered a best practice to internally complete the I/O task of actual async methods on a threadpool thread like so (pseudo code shown below for brevity and I'm using HttpClient as an example)

public Async Task<HttpResponseMessage> MyMethodAsync(..)
{
    ...
    var httpClient = new HttpClient(..);
    var response = await httpClient.PostAsJsonAsync(..).ConfigureAwait(false);
    ...
    return response;
}

The key here is the usage of ConfigureAwait(false) so that IO task completion occurs on a threadpool thread instead of on the original thread context, thereby potentially preventing deadlocks.

My question is from the perspective of a caller. I'm particularly interested in a scenario where there are layers of method calls between the caller and the above method call, as the following example shows.

CallerA -> Method1Async -> Method2Async -> finally the above MyMethodAsync

Is it enough to have ConfigureAwait(false) on the final method only or should one also ensure Method1Async and Method2Async also internally call their async methods with ConfigureAwait(false)? It seems silly to have it included on all these intermediary methods, especially if Method1Async and Method2Async are simply overloads that end up calling MyMethodAsync. Any thoughts, please enlighten us!

Updated with Example So if I have a library with the following private async method,

private async Task<string> MyPrivateMethodAsync(MyClass myClass)
{
    ...
    return await SomeObject.ReadAsStringAsync().ConfigureAwait(false);
}

should I make sure the following public overloaded methods both also include ConfigureAwait(false) as shown below?

public async Task<string> MyMethodAsync(string from)
{
        return await MyPrivateMethodAsync(new (MyClass() { From = from, To = "someDefaultValue"}).ConfigureAwait(false);
}
public async Task<string> MyMethodAsync(string from, string to)
{
        return await MyPrivateMethodAsync(new (MyClass() { From = from, To = to }).ConfigureAwait(false);
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Definitely not. ConfigureAwait just as it's name suggest configures the await. It only affects the await coupled with it.

ConfigureAwait actually returns a different awaitable type, ConfiguredTaskAwaitable instead of Task which in turn returns a different awaiter type ConfiguredTaskAwaiter instead of TaskAwaiter

If you want to disregard the SynchronizationContext for all your awaits you must use ConfigureAwait(false) for each of them.

If you want to limit the use of ConfigureAwait(false) you can use my NoSynchronizationContextScope (see here) at the very top:

async Task CallerA()
{
    using (NoSynchronizationContextScope.Enter())
    {
        await Method1Async();
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...