![](/img/trans.png)
[英]What are the differences between using ConfigureAwait(false) and Task.Run?
[英]Why ConfigureAwait(false) does not work while Task.Run() works?
我正在使用 ConfigureAwait(false) 调用异步库方法。 但是,我仍然以僵局告终。 (我在 ASP.NET 控制器 API 中使用它)但是,如果我使用包装到 Task.Run() 中的相同方法,它工作正常。
我的理解是,如果库方法在内部没有使用 ConfigureAwait,那么添加 ConfigureAwait 不会解决问题,因为在库调用中它会导致死锁(我们使用 .Result 阻止它)。 但是,如果是这种情况,为什么它会在 Task.Run() 中工作,因为它将无法在相同的上下文/线程中继续。
这篇文章谈到了它。 顺便说一句,我已经准备好了斯蒂芬克利里的大量文章。 但是,为什么 Task.Run() 起作用是个谜。
代码片段:
// This Create Method results in Deadlock
public async Task<string> Create(MyConfig config)
{
Document doc = await Client.CreateDocumentAsync(CollectionUri, config).ConfigureAwait(false);
return doc.Id;
}
// Uses Task.Run() which works properly, why??
public string Create(MyConfig config)
{
Document doc = Task.Run(() => Client.CreateDocumentAsync(CollectionUri, config)).Result;
return doc.Id;
}
[HttpPost]
public ActionResult CreateConfig(MyConfig config)
{
string id = Create(config).Result;
return Json(id);
}
我相信 Lukazoid 是正确的。 换个说法...
// This Create Method results in Deadlock
public async Task<string> Create(MyConfig config)
{
Document doc = await Client.CreateDocumentAsync(CollectionUri, config).ConfigureAwait(false);
return doc.Id;
}
你不能只在一个级别上粘贴一个ConfigureAwait(false)
并让它神奇地防止死锁。 只有在该方法及其调用的所有方法的传递闭包中的每个await
都使用它时, ConfigureAwait(false)
才能防止死锁。
换句话说, ConfigureAwait(false)
需要用于Create
每个await
(它是),并且它也需要用于CreateDocumentAsync
每个await
(我们不知道),并且它也需要用于CreateDocumentAsync
调用的每个方法中的每个await
等。
这就是为什么它是死锁问题的一个如此脆弱的“解决方案”的原因之一。
在第一个示例中, Client.CreateDocumentAsync
的实现是死锁的,因为它尝试使用当前SynchronizationContext
执行延续。
使用Task.Run
,将在 ThreadPool 线程上调用委托,这意味着将没有当前SynchronizationContext
因此将使用 ThreadPool 线程恢复所有延续。 这意味着它不会死锁。
出于兴趣,为什么您的CreateConfig
方法不是异步的? 最近的MVC和的WebAPI支持异步方法的版本,摆脱的.Result
将是最好的解决方案。
只是一个观察:我也注意到这样做也会导致死锁
private string Create(Task<Document> task)
{
var doc = Task.Run(() => task).Result;
return doc.Id;
}
[HttpPost]
public ActionResult CreateConfig(MyConfig config)
{
var task = Client.CreateDocumentAsync(CollectionUri, config);
var id = Create(task).Result;
return Json(id);
}
所以即使在线程池上运行东西也可能不是最终的解决方案。 它似乎认为一个同样进口的因素是什么SynchonizationContext
实际上是在创建异步方法的任务时。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.