Dav*_*ave 3 c# asynchronous async-await configureawait
我已经阅读了: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());
}
Run Code Online (Sandbox Code Playgroud)
如您所见,CloseLoadDoor 被声明为异步的。我认为(特别是从上面的第一篇文章)如果我使用 ConfigureAwait(false) 我可以调用异步方法而不会出现死锁。但这就是我似乎得到的。对“CloseLoadDoor().ConfigureAwait(false).GetAwaiter().GetResult() 的调用永远不会返回!
我正在使用 GetAwaiter.GetResult 因为 CancelCalibration 不是异步方法。这是一个通过 MVVM 模式定义的按钮处理程序:
public ICommand CancelCalibrationCommand
=> _cancelCalibrationCommand ?? (_cancelCalibrationCommand = new DelegateCommand(CancelCalibration));
Run Code Online (Sandbox Code Playgroud)
如果有人要告诉我我可以使 CancelCalibration 异步,请告诉我如何。我可以添加async到方法声明中吗?但是,我仍然想知道为什么这种ConfigureAwait.GetAwaiter.GetResult模式给我带来了麻烦。我的理解是,这GetAwaiter.GetResult是一种在无法更改签名时从同步方法调用异步方法的方法。
我猜我并没有真正摆脱使用原始上下文,但是我做错了什么以及修复它的模式是什么?谢谢,戴夫
我认为(特别是从上面的第一篇文章)如果我使用 ConfigureAwait(false) 我可以调用异步方法而不会出现死锁。
那篇文章中有一个重要的说明:
使用 ConfigureAwait(false) 来避免死锁是一种危险的做法。对于阻塞代码调用的所有方法的传递闭包中的每个等待,您必须使用 ConfigureAwait(false),包括所有第三方和第二方代码。使用 ConfigureAwait(false) 来避免死锁充其量只是一种黑客攻击)。
因此,被ConfigureAwait(false)用于每一个 await在传递闭包?这意味着:
CloseLoadDoor使用ConfigureAwait(false)每一个await?我们可以从发布的代码中看到它确实如此。_model.CloseLoadDoor使用ConfigureAwait(false)每一个await?我们看不到的。_model.CloseLoadDoor的使用ConfigureAwait(false),每await?_model.CloseLoadDoor使用ConfigureAwait(false)每一个await?这至少是一个严重的维护负担。我怀疑在调用堆栈的某个地方,缺少一个ConfigureAwait(false).
正如该笔记总结的那样:
正如这篇文章的标题所指出的,更好的解决方案是“不要阻塞异步代码”。
换句话说,那篇文章的重点是“不要阻塞异步代码”。这不是说“用这个巧妙的技巧阻止异步代码”。
如果您确实想要一个同时支持同步和异步调用者的 API,我建议在我关于 brownfield async 的文章中使用 bool 参数 hack 。
附带说明一下,在代码中CloseLoadDoor().ConfigureAwait(false).GetAwaiter().GetResult(),ConfigureAwait不做任何事情。它是“配置等待”,而不是“配置任务”。因为没有await,所以ConfigureAwait(false)没有效果。
| 归档时间: |
|
| 查看次数: |
6520 次 |
| 最近记录: |