在C#中与GetAwaiter和GetResult一起使用的ConfigureAwait(false)仍然很混乱。获取死锁或方法未返回

在C#中与GetAwaiter和GetResult一起使用的ConfigureAwait(false)仍然很混乱。获取死锁或方法未返回,c#,asynchronous,async-await,configureawait,C#,Asynchronous,Async Await,Configureawait,我读过:和 当时的答案是可以接受的,但我太过密集,看不清到底发生了什么 我有密码: private void CancelCalibration() { // ... TaskResult closeDoorResult = CloseLoadDoor().ConfigureAwait(false).GetAwaiter().GetResult(); CalibrationState = CalibrationState.Idle; return;

我读过:和 当时的答案是可以接受的,但我太过密集,看不清到底发生了什么

我有密码:

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());                
        }
如果有人要告诉我,我可以使CancelCalibration异步,请告诉我如何。我可以将
async
添加到方法声明中吗?然而,我仍然想知道为什么
ConfigureAwait.GetAwaiter.GetResult
模式给我带来麻烦。我的理解是,
GetAwaiter.GetResult
是一种在无法更改签名时从同步方法调用异步方法的方法

我猜我并没有真正从使用原始上下文中解脱出来,但我做错了什么?修复它的模式是什么? 谢谢 戴夫

我认为(特别是在上面的第一篇文章中),如果我使用ConfigureAwait(false),我可以在没有死锁的情况下调用异步方法

那篇文章中有一个重要的提示:

使用ConfigureWait(false)避免死锁是一种危险的做法。对于阻塞代码调用的所有方法(包括所有第三方和第二方代码)的传递闭包中的每个等待,都必须使用ConfigureAwait(false)。使用ConfigureAwait(false)来避免死锁充其量只是一种攻击)

那么,
ConfigureAwait(false)
是否用于传递闭包中的每个
await
?这意味着:

  • CloseLoadDoor
    是否对每个
    wait
    使用
    configurewait(false)
    ?我们可以从发布的代码中看出它确实如此
  • \u model.CloseLoadDoor
    是否为每个
    等待
    使用
    配置等待(false)
    ?我们看不见的
  • \u model.CloseLoadDoor调用的每个方法是否对每个
    等待
    使用
    配置等待(false)
  • \u model.CloseLoadDoor调用的每个方法调用的每个方法是否都对每个
    等待
    使用
    配置等待(false)
  • 等等
这至少是一个严重的维护负担。我怀疑调用堆栈中的某个地方缺少
ConfigureAwait(false)

正如该说明得出的结论:

正如这篇文章的标题所指出的,更好的解决方案是“不要阻塞异步代码”

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

如果您确实希望有一个同时支持同步和异步调用方的API,我建议您在中使用bool参数hack



另一方面,在代码
CloseLoadDoor().ConfigureAwait(false).GetAwaiter().GetResult()
中,
ConfigureAwait
没有任何作用。它是“配置等待”,而不是“配置任务”。由于那里没有
wait
,因此
configurewait(false)
没有任何效果。

所显示的代码没有死锁(模拟
\u model.CloseLoadDoor()
Task.Delay()
)。如果您使用
CancelCalibration
作为委托来命令它是一个逻辑事件处理程序,并且可以标记为
async void
,这将允许您
wait CloseDoor()
此异常包括逻辑上是事件处理程序的方法,即使它们不是真正的事件处理程序(例如,ICommand.Execute实现)有一种模式,不要编写无法调试的代码。异步的常见问题是,你不知道是否应该归咎于钉子的锤子。谢谢GSerg。我认为_model.CloseLoadDoor会立即返回。在本例中,这可能是正确的做法,但我想知道如何等待门被打开从未标记为async的函数关闭。谢谢!谢谢Stephen。我希望您能检查这个问题。我编辑了代码以显示调用的其他方法。它们都使用“ConfigureAwait(false)”,除非我们切换到同步代码并使用await Task.Run(()=>\u robot.CloseLoadDoors());没有ConfigureAwait。这可能是问题吗?Stephen,我被你的“旁注”评论弄糊涂了。也许我使用的是ConfigureAwait().GetAwaiter().GetResult()不正确?我的意图是等待CloseLoadDoor的结果。也许我没有这样做?我需要在这个调用中等待吗?或者以另一种方式询问问题…如果我告诉您由于某种奇怪的原因不能使用“wait”,您将如何编写对CloseLoadDoor()的调用。ConfigureWait(false)。GetWaiter()。GetResult()正确地模拟使用等待?我不理解你的评论:这是配置等待,而不是配置任务”。谢谢!我重新阅读了你的文章:在我看来,如果我不能保证配置等待(false)在堆栈中一直使用,我使用任务会更安全。运行(()=>CloseLoadDoor().GetAwaiter().GetResult();!当然在我的情况下,我可以将我的top方法更改为async并使用Wait,但正如你的文章所指出的,有时这可能无法完成。谢谢!@Dave:是的,错过了
等待任务的
配置等待(false)
。运行(…);
肯定会导致这里的死锁。
配置等待(false)的问题.GetAwaiter().GetResult()
是指
.ConfigureAwait(false)
在那里没有意义;它与没有
ConfigureAwait(false)的
.GetAwaiter().GetResult()
完全相同
。对于异步同步,没有完美的解决方案,但将其包装在
任务中。运行
并阻止它将适用于大多数代码。感谢Stephen。我现在非常清楚。在现实世界中,这仍然是一个非常困难的问题,因为人们无法始终保证“等待…配置等待(false)”“一直以来都在使用。人们甚至可能看不到代码(隐藏在库中)或由于某种原因无法更改它。
public ICommand CancelCalibrationCommand
        => _cancelCalibrationCommand ?? (_cancelCalibrationCommand = new DelegateCommand(CancelCalibration));