异步库最佳实践:ConfigureAwait(false)与设置同步上下文

时间:2016-09-12 09:48:00

标签: c# asynchronous async-await

众所周知,在通用库中,每次await调用都应使用ConfigureAwait(false),以避免继续使用当前的SynchronizationContext。

作为使用ConfigureAwait(false)加密整个代码库的替代方法,可以在公共表面方法中将SynchronizationContext设置为null一次,并在返回给用户之前将其恢复。换句话说:

public async Task SomeSurfaceMethod()
{
    var callerSyncCtx = SynchronizationContext.Current;
    SynchronizationContext.SetSynchronizationContext(null);
    try
    {
        // Do work
    }
    finally
    {
        SynchronizationContext.SetSynchronizationContext(callerSyncCtx);
    }
}

这也可以包含在using中,以提高可读性。

这种方法是否有缺点,它最终不会产生相同的效果吗?

主要优势显然是可读性 - 删除所有ConfigureAwait(false)个电话。它还可以降低忘记ConfigureAwait(false)某处的可能性(尽管分析人员可以减轻这种情况,并且可以说开发人员也可以忘记更改SynchronizationContext)。

有点奇特的优点是没有嵌入在所有方法中捕获SynchronizationContext的选择。换句话说,在一种情况下,我可能想要使用SynchronizationContext运行方法X,而在另一种情况下,我可能想要运行相同的方法而没有一个。当ConfigureAwait(false)被嵌入到无法实现的任何地方时。当然,这是一个非常罕见的要求,但我在处理Npgsql时遇到了这个问题(触发了这个问题)。

1 个答案:

答案 0 :(得分:0)

正如@MrinalKamboj在评论中所写,已经提出了在公共表面方法和设置中暂时将SynchronizationContext设置为null的方法here。似乎没有任何与此相关的特定问题(请参阅Stephen Cleary's answer here)。