我正在使用 .ConfigureAwait(false)
调用一个 async
库方法。但是,我仍然陷入僵局。 (我在 ASP.NET Controller API 中使用它)
但是,如果我使用包装到 Task.Run()
中的相同方法,它就可以正常工作。
我的理解是,如果库方法没有在内部使用 ConfigureAwait
那么添加 ConfigureAwait
不会解决问题,因为在库调用中会导致死锁 (我们使用 .Result
阻止它)。但是,如果是这种情况,为什么它在 Task.Run()
中工作,因为它将无法在相同的上下文/线程中继续。
这article谈论它。顺便说一句,我读了很多 Stephen Cleary 的文章。但是,为什么 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)
并让它神奇地防止死锁。 ConfigureAwait(false)
只有在该方法及其调用的所有方法的传递闭包中被每个 await
使用时才能防止死锁。
换句话说,ConfigureAwait(false)
需要用于 Create
中的每个 await
(确实如此),并且它还需要用于 CreateDocumentAsync
中的每个 await
(我们不知道),并且还需要用于每个 await
CreateDocumentAsync
调用的每个方法,等等。
这就是为什么它是死锁问题如此脆弱的“解决方案”的原因之一。
关于c# - 为什么 ConfigureAwait(false) 在 Task.Run() 有效时不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36654472/