根据许多书籍和博客(包括这里的优秀文章),很明显,当编写一个公开辅助异步方法(即包装器方法)的 dll 库时,通常认为在内部完成实际异步方法的 I/O 任务是一种最佳实践在这样的线程池线程上(为简洁起见,下面显示的伪代码,我HttpClient
用作示例)
public Async Task<HttpResponseMessage> MyMethodAsync(..)
{
...
var httpClient = new HttpClient(..);
var response = await httpClient.PostAsJsonAsync(..).ConfigureAwait(false);
...
return response;
}
这里的关键是使用ConfigureAwait(false)
IO 任务完成发生在线程池线程上,而不是在原始线程上下文上,从而潜在地防止死锁。
我的问题是从呼叫者的角度来看的。我对调用者和上述方法调用之间存在多层方法调用的场景特别感兴趣,如下面的示例所示。
CallerA -> Method1Async -> Method2Async -> finally the above MyMethodAsync
仅使用 final 方法就足够了,ConfigureAwait(false)
还是应该确保Method1Async
并Method2Async
在内部调用它们的异步方法ConfigureAwait(false)
?将它包含在所有这些中间方法中似乎很愚蠢,尤其是如果Method1Async
并且Method2Async
只是最终调用MyMethodAsync
. 有什么想法,请赐教!
使用示例更新 因此,如果我有一个具有以下私有异步方法的库,
private async Task<string> MyPrivateMethodAsync(MyClass myClass)
{
...
return await SomeObject.ReadAsStringAsync().ConfigureAwait(false);
}
我应该确保以下公共重载方法都包括 ConfigureAwait(false) ,如下所示?
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);
}