[英]Set SynchronizationContext to null instead of using ConfigureAwait(false)
I have a library that exposes synchronous and asynchronous versions of a method, but under the hood, they both have to call an async method.我有一个公开方法的同步和异步版本的库,但在幕后,它们都必须调用异步方法。 I can't control that async method (it uses async/await and does not use
ConfigureAwait(false)
), nor can I replace it.我无法控制异步方法(它采用异步/ AWAIT并且不使用
ConfigureAwait(false)
),我也可以取代它。
The code executes in the context of an ASP .NET request, so to avoid deadlocks, here's what I've done:代码在 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);
}
Does this produce the same effect as if MyMethodAsync had used ConfigureAwait(false)
on all of its await's?这是否会产生与 MyMethodAsync 在其所有 await 上使用
ConfigureAwait(false)
相同的效果? Are there some other problems with this approach that I'm overlooking?我忽略了这种方法还有其他一些问题吗?
(MyMethodAsync is completely unaware that it's being run in an ASP .NET context, it doesn't do any calls to HttpContext.Current
or anything like that. It just does some async SQL calls, and the writer didn't put ConfigureAwait(false)
on any of them) (MyMethodAsync 完全不知道它是在 ASP .NET 上下文中运行的,它不会调用
HttpContext.Current
或类似的东西。它只是执行一些异步 SQL 调用,并且作者没有将ConfigureAwait(false)
在其中任何一个上)
I have a library that exposes synchronous and asynchronous versions of a method, but under the hood, they both have to call an async method.
我有一个公开方法的同步和异步版本的库,但在幕后,它们都必须调用异步方法。
The library is wrong to expose a synchronous version . 该库公开同步版本是错误的。 Just pretend the synchronous API doesn't exist.
假设同步 API 不存在。
so to avoid deadlocks
所以为了避免死锁
There shouldn't be any problems with deadlocks if you call an asynchronous method that uses async
/ await
.如果您调用使用
async
/ await
的异步方法,死锁应该不会有任何问题。 If it doesn't use ConfigureAwait(false)
, then it's not as efficient as it could be, that's all.如果它不使用
ConfigureAwait(false)
,那么它的效率就不会那么高,仅此而已。 Deadlocks due to ConfigureAwait(false)
only apply when you're trying to do sync-over-async (ie, if you're calling the synchronous APIs from that library).由于
ConfigureAwait(false)
导致的死锁仅在您尝试执行异步同步时适用(即,如果您从该库调用同步 API)。
So, the easiest and simplest solution is to just ignore the synchronous APIs, which are incorrectly designed anyway:因此,最简单和最简单的解决方案是忽略同步 API,它们无论如何都是错误设计的:
return await MyMethodAsync();
Provided you wrap this technique in a suitably named static function, I think your suggest is significantly better than Task.Run
, even if still the lesser of two evils.如果您将此技术包装在一个适当命名的静态函数中,我认为您的建议明显优于
Task.Run
,即使仍然是两害相权取其Task.Run
。
Task.Run
has a number of issues: Task.Run
有很多问题:
SetSynchronizationContext
there's no harm in doing it more than once).SetSynchronizationContext
没有坏处)。Task.Run
now is introducing blocking over async, whereas SetSynchronizationContext
will not cost you anything, in addition to the optimizations it makes by not resuming on the context constantly.Task.Run
现在将通过异步引入阻塞,而SetSynchronizationContext
不会花费您任何费用,除了它通过 not 进行的优化之外不断地恢复上下文。 I also understand there is hesitance to make any recommendation given blocking on async code should be avoided at all costs, however you have made it clear you are aware of this and this is to fix a known case of this outside of your immediate control.我也理解在不惜一切代价避免阻塞异步代码的情况下提出任何建议时犹豫不决,但是您已经明确表示您知道这一点,这是为了解决您无法直接控制的已知情况。 I think the dogmatic attitude towards this topic is damaging to the .NET ecosystem.
我认为对这个话题的教条态度正在损害 .NET 生态系统。
Setting the SynchronizationContext
to null seems hacky for me.将
SynchronizationContext
设置为 null 对我来说似乎很棘手。 Instead you can really delegate the work to threadpool.相反,您可以真正将工作委托给线程池。 Use
Task.Run
..使用
Task.Run
..
var result = Task.Run(() => MyMethodAsync()).Result;
or或者
var result = Task.Run(async () => await MyMethodAsync()).Result;
This avoids the deadlock and eliminates the hacky code as well.这避免了死锁并消除了hacky代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.