[英]Can async/await still deadlock if ConfigureAwait(false) is used?
[英]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.