繁体   English   中英

仍然对与C#中的GetAwaiter和GetResult一起使用的ConfigureAwait(false)感到困惑。 使死锁或方法不返回

[英]Still confused on ConfigureAwait(false) used with GetAwaiter and GetResult in C#. Getting a deadlock or method not returning

我已经读过: http : //blog.stephencleary.com/2012/07/dont-block-on-async-code.html死锁的公认答案, 即使在Asp.Net流中使用ConfigureAwait(false)之后,也只是太稠密,看不到发生了什么事。

我有代码:

private void CancelCalibration()
{
    // ...
    TaskResult closeDoorResult =  CloseLoadDoor().ConfigureAwait(false).GetAwaiter().GetResult(); 
    CalibrationState = CalibrationState.Idle;

    return;
    // ...                   
}

private async Task<TaskResult> CloseLoadDoor()
{       
    TaskResult result = await _model.CloseLoadDoor().ConfigureAwait(false);           
    return result;
}
public async Task<TaskResult> CloseLoadDoor()
    {
        TaskResult result = new TaskResult()
        {
            Explanation = "",
            Success = true
        };
        await _robotController.CloseLoadDoors().ConfigureAwait(false);
        return result;
    }
    public async Task CloseLoadDoors()
    {                         
            await Task.Run(() => _robot.CloseLoadDoors());              
    }

     public void CloseLoadDoors()
    {
   // syncronous code from here down              
   _doorController.CloseLoadDoors(_operationsManager.GetLoadDoorCalibration());                
        }

如您所见,CloseLoadDoor被声明为异步。 我以为(特别是从以上第一篇文章中)我可以通过使用ConfigureAwait(false)来调用一个没有死锁的异步方法。 但这就是我似乎得到的。 对“ CloseLoadDoor()。ConfigureAwait(false).GetAwaiter()。GetResult()的调用永远不会返回!

我正在使用GetAwaiter.GetResult,因为CancelCalibration不是异步方法。 它是通过MVVM模式定义的按钮处理程序:

public ICommand CancelCalibrationCommand
        => _cancelCalibrationCommand ?? (_cancelCalibrationCommand = new DelegateCommand(CancelCalibration));

如果有人要告诉我可以使CancelCalibration异步,请告诉我如何。 我可以将async添加到方法声明中吗? 但是,我仍然想知道为什么ConfigureAwait.GetAwaiter.GetResult模式给我带来麻烦。 我的理解是,当不能选择更改签名时, GetAwaiter.GetResult是一种从同步方法中调用异步方法的方法。

我猜我并没有真正从使用原始上下文中解放出来,但是我在做错什么,以及解决该问题的模式是什么? 谢谢戴夫

我以为(特别是从以上第一篇文章中)我可以通过使用ConfigureAwait(false)来调用一个没有死锁的异步方法。

那篇文章有一个重要的说明:

使用ConfigureAwait(false)避免死锁是一种危险的做法。 在阻塞代码调用的所有方法( 包括所有第三方代码和第二方代码 )的传递关闭中,您必须为每次等待使用ConfigureAwait(false)。 使用ConfigureAwait(false)避免死锁充其量只是一种破解)。

那么,是否在传递闭包中为每个 await使用ConfigureAwait(false) 这意味着:

  • CloseLoadDoor是否每次await都使用ConfigureAwait(false) 从发布的代码中我们可以看到它确实如此。
  • _model.CloseLoadDoor是否每次await都使用ConfigureAwait(false) 我们看不到。
  • _model.CloseLoadDoor调用的每个方法是否都为每次await使用ConfigureAwait(false)
  • _model.CloseLoadDoor调用的每个方法调用的每个方法是否都对每次await使用ConfigureAwait(false)
  • 等等

至少这是一个沉重的维护负担。 我怀疑在调用堆栈的某个地方,缺少一个ConfigureAwait(false)

该注释总结如下:

正如该帖子的标题所指出的那样,更好的解决方案是“不要阻止异步代码”。

换句话说,该文章的重点是“不要阻止异步代码”。 这并不是说“使用这一巧妙技巧阻止异步代码”。

如果您确实想拥有一个同时支持同步和异步调用者的API,建议在我关于brownfield async的文章中使用bool参数hack。


附带说明一下,在代码CloseLoadDoor().ConfigureAwait(false).GetAwaiter().GetResult()ConfigureAwait不会执行任何操作。 它是“等待配置”,而不是“配置任务”。 由于那里没有await ,因此ConfigureAwait(false)无效。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM