我一直在开发一些将由MVC操作方法使用的库代码,所以我一直在阅读很多关于这个主题的Steven Cleary的博客。
我参加了他的“Don't Block on Async Code”博客文章,但我对一些似乎相互矛盾的部分感到困惑。
在“防止僵局”下,他说:
有两个最佳实践(我的介绍帖中都有) 避免这种情况:
在“库”异步方法中,无论何处使用ConfigureAwait(false) 可能。
- 醇>
不要阻止任务;一直使用async。
然后:
使用ConfigureAwait(false)来避免死锁是一件危险的事情 实践。您必须为每个await使用ConfigureAwait(false) 在阻塞代码调用的所有方法的传递闭包中, 包括所有第三方和第二方代码。运用 ConfigureAwait(false)以避免死锁充其量只是一个hack)。
鉴于这两个陈述,有人说ConfigureAwait(false)
是库代码的最佳实践,并且说它充其量只是一个危险的黑客,编写库代码的实际正确方法是什么?在MVC中使用死锁?
我已经阅读了其他问题和答案,因为可能被认为是重复的,但它们似乎都没有解决其中一位专家在async / await上提供的矛盾信息。 / p>
答案 0 :(得分:3)
除非您将这些信息脱离背景,否则这些信息不会直接相互矛盾:
前者是编写库代码的一般建议;做这些事情是个好主意,以确保你的图书馆表现良好,无论它被调用的同步环境如何。
后者明确地提到如何使用ConfigureAwait(false)
作为避免已知死锁场景的手段。它说,
我想在这里阻止,但这样做通常会导致死锁,所以我将工作推送到另一个线程(来自线程池)并希望一切正常。
如果遵循早先的建议不阻止任务(一直使用异步),那么这种死锁情况就不会发生。
死锁场景仅在特定同步上下文中运行代码时相关,该特定同步上下文在启动任务的线程上安排继续执行,例如ASP.NET使用的(在一个线程上处理请求)或者Windows桌面应用程序使用(所有UI事件的单个线程)。
在这些上下文中阻塞任务会导致单个线程被阻塞,因此线程永远不会自由运行continuation和方法死锁。