[英]Set SynchronizationContext to null instead of using ConfigureAwait(false)
我有一个公开方法的同步和异步版本的库,但在幕后,它们都必须调用异步方法。 我无法控制异步方法(它采用异步/ AWAIT并且不使用ConfigureAwait(false)
),我也可以取代它。
代码在 ASP .NET 请求的上下文中执行,因此为了避免死锁,我做了以下工作:
var capturedContext = SynchronizationContext.Current;
try
{
// Wipe the sync context, so that the bad library code won't find it
// That way, we avoid the deadlock
SynchronizationContext.SetSynchronizationContext(null);
// Call the async method and wait for the result
var task = MyMethodAsync();
task.Wait();
// Return the result
return task.Result;
}
finally
{
// Restore the sync context
SynchronizationContext.SetSynchronizationContext(capturedContext);
}
这是否会产生与 MyMethodAsync 在其所有 await 上使用ConfigureAwait(false)
相同的效果? 我忽略了这种方法还有其他一些问题吗?
(MyMethodAsync 完全不知道它是在 ASP .NET 上下文中运行的,它不会调用HttpContext.Current
或类似的东西。它只是执行一些异步 SQL 调用,并且作者没有将ConfigureAwait(false)
在其中任何一个上)
我有一个公开方法的同步和异步版本的库,但在幕后,它们都必须调用异步方法。
该库公开同步版本是错误的。 假设同步 API 不存在。
所以为了避免死锁
如果您调用使用async
/ await
的异步方法,死锁应该不会有任何问题。 如果它不使用ConfigureAwait(false)
,那么它的效率就不会那么高,仅此而已。 由于ConfigureAwait(false)
导致的死锁仅在您尝试执行异步同步时适用(即,如果您从该库调用同步 API)。
因此,最简单和最简单的解决方案是忽略同步 API,它们无论如何都是错误设计的:
return await MyMethodAsync();
如果您将此技术包装在一个适当命名的静态函数中,我认为您的建议明显优于Task.Run
,即使仍然是两害相权取其Task.Run
。
Task.Run
有很多问题:
SetSynchronizationContext
没有坏处)。Task.Run
现在将通过异步引入阻塞,而SetSynchronizationContext
不会花费您任何费用,除了它通过 not 进行的优化之外不断地恢复上下文。我也理解在不惜一切代价避免阻塞异步代码的情况下提出任何建议时犹豫不决,但是您已经明确表示您知道这一点,这是为了解决您无法直接控制的已知情况。 我认为对这个话题的教条态度正在损害 .NET 生态系统。
将SynchronizationContext
设置为 null 对我来说似乎很棘手。 相反,您可以真正将工作委托给线程池。 使用Task.Run
..
var result = Task.Run(() => MyMethodAsync()).Result;
或者
var result = Task.Run(async () => await MyMethodAsync()).Result;
这避免了死锁并消除了hacky代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.