我已经阅读了很多关于 async/await 编程模型的文章,但仍有一些不太清楚的地方,我想分享一下我对这些问题的困惑。
假设我们有以下配置:
主要的异步方法是 public async Task<bool> DoSomethingBigAsync(){...}
,它内部有 3 个其他方法,如下所示:
A) var a = await _someInstance.DoSomethingLittle_A_Async().ConfigureAwait(false);
B) var b = await _someInstance.DoSomethingLittle_B_Async();
C) var c = _someInstance.DoSomethingLittle_C();
比方说,从 UI 线程调用 main 方法。我们知道上下文将被捕获,当 main 方法完成时,上下文将被恢复。
如果我没记错的话,当第一个 ( A ) 异步方法被调用时,由于 ConfigureAwait(false)
的原因,UI 上下文不会被捕获,而是将延续从池中推送到一个线程。但这不能保证一定会发生,因为调用可能会立即完成。出于这个原因,我怀疑应该在所有内部异步方法上调用 ConfigureAwait(false)
(在本例中为 A 和 B )。这是正确的,还是运行时在看到对 ConfigureAwait(false)
的第一次调用后知道要做什么?
我的另一个担忧是关于两种不良做法(或认为如此)及其副作用。
根据 Stephen Toub 的文章,一种不好的做法似乎是:
出于这个原因,制作 DoSomethingLittle_C()
方法的异步版本并不是一个好主意。
另一个不好的做法似乎是:
现在,查看上面的代码,如果第一个 ConfigureAwait(false)
可以保证将延续推送到线程池,我将看不到使用 Task.StartNew(() => { c = _someInstance.DoSomethingLittle_C(); })
的附加值。
另一方面,如果 ConfigureAwait(false)
从不保证将延续推送到线程池,那么我们可能会遇到问题,我们必须确保使用 Task.StartNew(() => { c = _someInstance.DoSomethingLittle_C(); })
。
错误的(?):
A) var a = await _someInstance.DoSomethingLittle_A_Async().ConfigureAwait(false);
B) var b = await _someInstance.DoSomethingLittle_B_Async();
C) var c = _someInstance.DoSomethingLittle_C();
正确的(?):
A) var a = await _someInstance.DoSomethingLittle_A_Async().ConfigureAwait(false);
B) var b = await _someInstance.DoSomethingLittle_B_Async().ConfigureAwait(false);
C) var c = Task.StartNew(() => {return _someInstance.DoSomethingLittle_C();});
最佳答案
是的。这应该。因为,正如您所说,前一个调用可能会同步完成,也因为前一个调用将来可能会更改,您不想依赖它。
关于 Task.Run
(它比 Task.Factory.StartNew
更受欢迎),问题是是否在 API 的实现中使用它,答案几乎总是不。
你的情况不同。如果您在 UI 线程上并且您有大量工作(Stephen Cleary 的建议超过 50 毫秒)可以在后台完成,那么将这些工作卸载到 ThreadPool
线程以保持 UI 响应并没有错。就像 ConfigureAwait
一样,我不会依赖前面的调用将您移至 ThreadPool
,因为它也可以同步完成。
所以,更正:
var a = await _someInstance.DoSomethingLittle_A_Async().ConfigureAwait(false);
var b = await _someInstance.DoSomethingLittle_B_Async().ConfigureAwait(false);
var c = await Task.Run(() => _someInstance.DoSomethingLittle_C()).ConfigureAwait(false);
关于c# - ConfigureAwait 和混合异步与同步调用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31672308/