仍然对C#中与GetAwaiter和GetResult一起使用的ConfigureAwait(false)感到困惑.获取



我已经阅读了: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被声明为async。我认为(尤其是在上面的第一篇文章中),如果我使用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是从同步方法调用异步方法的一种方式。

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

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

这篇文章中有一个重要的注释:

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

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

  • 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参数破解。


附带说明一下,在代码CloseLoadDoor().ConfigureAwait(false).GetAwaiter().GetResult()中,ConfigureAwait什么都不做。它是"配置等待",而不是"配置任务"。因为那里没有await,所以ConfigureAwait(false)没有任何作用。

相关内容

  • 没有找到相关文章

最新更新