【发布时间】:2015-11-23 00:16:37
【问题描述】:
使用await 时,默认情况下会捕获SynchronizationContext(如果存在),并使用该上下文执行await(延续块)之后的代码块(这会导致线程上下文切换)。
public async Task DoSomethingAsync()
{
// We are on a thread that has a SynchronizationContext here.
await DoSomethingElseAsync();
// We are back on the same thread as before here
//(well sometimes, depending on how the captured SynchronizationContext is implemented)
}
虽然在您希望在异步操作完成后返回 UI 线程的 UI 上下文中,此默认设置可能有意义,但对于大多数其他情况,默认设置似乎没有意义。这对于内部库代码当然没有意义,因为
在我看来,微软已经决定使用错误的默认值。
现在我的问题:
除了将我的代码中的所有await 调用与.ConfigureAwait(false) 混淆之外,还有其他(最好是更好的)方法来解决这个问题吗?这很容易忘记,并且使代码的可读性降低。
更新:
在每个方法的开头调用await Task.Yield().ConfigureAwait(false); 可能就足够了吗?如果这可以保证我将在没有SynchronizationContext aferwards 的线程上,那么所有后续的await 调用都不会捕获任何上下文。
【问题讨论】:
-
当然是一个非常丑陋的全局变量。揭示了添加 async/await 的真正原因,它为程序员提供了编写 WinRT 代码而不是死的机会。不是错误的默认值。作为一种处理异步性的通用机制,嗯,不是真的。任何线程抽象都会增加五个新的难以调试的问题。让它看起来太容易会很危险。
-
您是否建议最好避免在库代码中使用 async/await?
-
关于这个:
// We are back on the same thread as before here.- 不一定在同一个线程上。它可能不是 ASP.NET 中的同一个线程,但仍然是同一个同步上下文。 -
@Noseratio 你说得对。
-
Task.Yield().ConfigureAwait(false) 无法编译。 Yield 不返回任务,它返回一个特制的等待对象。而且它不会让你脱离同步环境。
标签: c# .net async-await c#-5.0