c# - 为什么 ConfigureAwait(false) 在 Task.Run() 有效时不起作用?

标签 c# async-await configureawait

我正在使用 .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/

相关文章:

正则表达式查找丢失的 ConfigureAwait

c# - 如何正确阻止异步代码?

c# - 使用 async/await 时如何避免 UI 线程上的竞争条件

javascript - 有没有更干净的方法来获取 Promise 的错误和结果

c# - 如何制作使用同一程序集中的静态变量的动态方法?

c# - DataContract 与消息合约

python - 多个异步调用阻塞

c# - 如果异步调用不一定在不同的线程上执行,那么阻塞异步调用如何会导致死锁?

c# - g.i.cs 类不断将其基类更改回默认值

c# - 如何使用C#代码在winCE中创建快捷方式?