前瞻警告:
我完全清楚在下面显示的上下文中使用.Result是错误的,应该不惜一切代价避免使用.Result。我知道正确的方法是什么。
这个问题的本质更多地与db-drivers的基础结构有关:Oracle vs Ms-Sql-Server。这在很大程度上是一个学术问题。
System.Web.MVC.dll: ver. 5.2.3.0 (MVC5)
EntityFramework.dll: ver. 6.1.3
EntityFramework.SqlServer.dll: ver. 6.1.3
Oracle.ManagedDataAccess: ver. 4.121.2.0 (oracle driver ver 12.2.0.1.0)
Oracle.ManagedDataAccess.EntityFramework: ver. 6.121.2.0 (oracle driver ver 12.2.0.1.0)
考虑以下存储库及其在ASP.NET MVC控制器中的调用:
public class MyRepository {
[...]
public async Task<SomeEntity> GetFirstFooAsync() => await new SomeEFContext().FooTable.FirstOrDefaultAsync();
}
public class SomeController : Controller {
public ActionResult SomeAction() {
var result = new MyRepository.GetFirstFooAsync().Result; //<-- crappy approach I know
[...]
}
}
当底层数据库是Oracle时,上面的代码不会死锁。但是,当通过MS为EF提供的相关驱动程序定位MS-Sql-Server时,这段完全相同的代码会导致死锁。
死锁是这种糟糕代码的预期行为
为什么oracle-driver不会造成死锁?它是在内部使用.ConfigureAwait(false)
还是其他一些调整?
如果oracle驱动程序确实使用了调整,我应该担心它可能会产生不良的副作用,即使在适当地编程调用时也是如此
public class SomeController : Controller {
public async Task<ActionResult> SomeAction() {
var result = await new MyRepository.GetFirstFooAsync();
[...]
}
}
我之所以这样问,是因为我认为互联网智慧反对使用.ConfigureAwait(false)
&#34;部分&#34;因此,我应该在所有其他异步调用(如果有)中使用.ConfigureAwait(false)
,即使它们针对其他组件。我不确定我是否正确理解/解释上述建议 - 我很乐意予以纠正。如果我有理由担心,请非常友好地提供一个示例,其中部分使用.ConfigureAwait(false)
会导致问题,并提供一个示例,说明.ConfigureAwait(false)
在多个Async()
时的使用方式涉及调用。
答案 0 :(得分:0)
ConfigureAwait(false)
不会阻止这种僵局。
我推测Oracle可能是在Task.Run
(或类似的东西)中包含的同步代码异步同步。
ConfigureAwait(false)
(因为它没有同步上下文),不应在action方法中使用,因为在退出action方法后需要上下文。
你可以尝试这个(我没有)看看它是否适用于两个提供者:
public class SomeController : Controller
{
public ActionResult SomeAction()
{
var synchronizationContext = SynchronizationContext.Current;
try
{
var result = new MyRepository.GetFirstFooAsync().Result;
[...]
}
finally
{
SynchronizationContext.SetSynchronizationContext(synchronizationContext);
}
}
}
答案 1 :(得分:0)
https://community.oracle.com/thread/4092961
胡扯。甲骨文在拉我们的脚。他们对异步/等待没有任何尊重。他们在内部诉诸阻塞呼叫,就好像在任何地方都没有使用异步/等待一样。 “好极了”。