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