Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/298.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从单独的程序集调用异步扩展方法_C#_.net_Asynchronous_.net Standard - Fatal编程技术网

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
  • 一个使用1号组件的组件。目标是.NETFramework4.7
  • 出于某种原因,从程序集2到程序集1使用同步方法会导致奇怪的行为。考虑第1号汇编中的两个函数:

        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);
    }