C# 从单独的程序集调用异步扩展方法
我在单独的程序集中遇到了一个关于异步扩展方法的奇怪行为 我们有以下几点:C# 从单独的程序集调用异步扩展方法,c#,.net,asynchronous,.net-standard,C#,.net,Asynchronous,.net Standard,我在单独的程序集中遇到了一个关于异步扩展方法的奇怪行为 我们有以下几点: 一个程序集处理EventGridEvent的发送。目标是.NET标准2.0。此程序集引用了Microsoft.Azure.EventGrid 一个使用1号组件的组件。目标是.NETFramework4.7 出于某种原因,从程序集2到程序集1使用同步方法会导致奇怪的行为。考虑第1号汇编中的两个函数: public async Task PublishAsync(...) { await _ev
EventGridEvent
的发送。目标是.NET标准2.0。此程序集引用了Microsoft.Azure.EventGrid public async Task PublishAsync(...)
{
await _eventGridClient.PublishEventsAsync(_eventGridTopicHostName, ...);
}
public void Publish(...)
{
_eventGridClient.PublishEventsAsync(_eventGridTopicHostName, ...).Wait();
}
如果我们使用PublishAsync().Wait()
调用程序集2中的第一个方法,它将永远不会返回<但是,代码>发布()将。但是,如果Publish()
调用PublishAsync().Wait()
,该方法也将挂起
值得一提的是,EventGridClient
包含LongRunningOperationRetryTimeout
,默认设置为30,该值被忽略。它永远不会回来
有人知道是什么导致了这种行为吗?一种解决方法是复制代码,但我们希望避免这种情况
提前感谢。您不应该通过调用返回的
任务的Wait()
或.Result
来阻止异步代码@斯蒂芬·克利里解释了原因
调用\u eventGridClient.PublishEventsAsync
时,将捕获同步上下文。当任务完成时,它会等待上下文变为可用,但它永远不会变为可用,因为您正在通过调用.Wait()
阻止它。这导致了僵局
通过调用ConfigureAwait(false)
,可以避免捕获上下文,从而避免麻烦:
但最好的解决办法仍然是根本不堵塞。异步代码应该是“一路异步”,正如链接的博客文章中所解释的。问题是调用方法在UI线程上运行。通过如下方式包装调用解决了此问题:Task.Run(()=>…).Wait()
您在PublishEventsAsync
中有什么内容?您不应该对任务调用Wait()
或Result
,因为它可能导致死锁和奇怪的异常行为:为什么要调用Wait()
?这是个坏主意。您应该等待或忽略任务,但不要阻止它。加上1表示“始终异步”。等待/结果都是最纯粹的邪恶。理想情况下,你应该一直保持异步,但如果出于某种原因这是不可能的,那么当你没有需要使用的方法的非异步版本时,使用.Result
也没什么大不了的。@howcheng:那么你把死锁称为“没什么大不了的”?有意思。@mm8我想我没那么清楚。如果您从一个非异步方法开始,到了没有所需方法的非异步版本的地步,那么使用.Result
将不会导致死锁。当然,最好使调用堆栈中的第一项异步,但有时这是不可能的。
public async Task PublishAsync(...)
{
await _eventGridClient.PublishEventsAsync(_eventGridTopicHostName, ...)
.ConfigureAwait(false);
}