我经常使用 异步/等待 以确保 ASP.NET MVC Web API 线程不会被长时间运行的 I/O 和网络操作(特别是数据库调用)阻塞。
System.Data.Entity namespace 在这里提供了多种辅助扩展,例如 FirstOrDefaultAsync、ContainsAsync、CountAsync 等。
但是,由于数据上下文不是线程安全的,这意味着以下代码有问题:
var dbContext = new DbContext();
var something = await dbContext.someEntities.FirstOrDefaultAsync(e => e.Id == 1);
var morething = await dbContext.someEntities.FirstOrDefaultAsync(e => e.Id == 2);
System.InvalidOperationException: The connection was not closed. The connection's current state is open.
using(new DbContext...)
是正确的模式吗?为每个对数据库的异步调用阻塞?那么只执行同步是否可能更有益?
我们在这里陷入了僵局。 AspNetSynchronizationContext
,负责ASP.NET Web API执行环境的线程模型,不保证await
之后的异步继续。将在同一线程上进行。这样做的整个想法是使 ASP.NET 应用程序更具可扩展性,从而减少来自 ThreadPool
的线程。被挂起的同步操作阻塞。
然而, DataContext
class (part of LINQ to SQL )
不是线程安全的,因此不应在可能跨 DataContext
发生线程切换的地方使用它。 API 调用。单独的 using
构造每个异步调用将 不是 帮助,或者:
var something;
using (var dataContext = new DataContext())
{
something = await dataContext.someEntities.FirstOrDefaultAsync(e => e.Id == 1);
}
DataContext.Dispose
可能会在与最初创建对象的线程不同的线程上执行,这不是 DataContext
会期待。DataContext
API,调用它 同步似乎是唯一可行的选择。我不确定该语句是否应该扩展到整个 EF API,但我想任何使用 DataContext
创建的子对象API 也可能不是线程安全的。因此,在 ASP.NET 中,他们的 using
范围应限制在两个相邻 await
之间的范围内调用。DataContext
可能很诱人使用 await Task.Run(() => { /* do DataContext stuff here */ })
调用单独的线程.但是,那将是 a known anti-pattern ,尤其是在 ASP.NET 的上下文中,它可能只会损害性能和可伸缩性,因为它不会减少满足请求所需的线程数。DataContext
同时对象。关于c# - EF 数据上下文 - 异步/等待和多线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20946677/
欢迎光临 OStack程序员社区-中国程序员成长平台 (https://ostack.cn/) | Powered by Discuz! X3.4 |