最近,我们升级到EF6跳转,以利用webapi控制器中的异步调用,但经过一些在线阅读,我可以知道。
- EF6 async call is not thread safe
While thread safety would make async more useful it is an orthogonal feature. It is
unclear that we could ever implement support for it in the most general case, given that
EF interacts with a graph composed of user code to maintain state and there aren't
easy ways to ensure that this code is also thread safe.但在这个问题中,EF数据上下文-异步/等待和多线程也表达了同样的观点
但是,当我查看来自MS http://msdn.microsoft.com/en-us/data/jj819165.aspx的示例时,我感到困惑,因为如果我查看堆栈溢出问题中提供的答案,那么我们目前似乎没有任何解决方案/模式来实现它--使用单个db上下文来实现线程安全?
所以我的问题是如何实现
var dbContext = new DbContext();
var something = await dbContext.someEntities.FirstOrDefaultAsync(e => e.Id == 1);
var morething = await dbContext.someEntities.FirstOrDefaultAsync(e => e.Id == 2);线程安全功能是正确的吗?
发布于 2014-05-26 06:47:15
你引用的相同的EF文档:
目前,EF将检测开发人员是否试图一次执行两个异步操作并抛出。
因此,即使在await之后有一个线程开关,这段代码也可以工作,因为它仍然是按顺序执行的:
var dbContext = new DbContext();
var something = await dbContext.someEntities.FirstOrDefaultAsync(e => e.Id == 1);
var morething = await dbContext.someEntities.FirstOrDefaultAsync(e => e.Id == 2);至少,这是预期的工作方式。如果顺序执行仍然会产生与线程相关的异常,则应将其报告为EF错误。
另一方面,以下代码很可能会失败,因为我们引入了并行性:
var dbContext = new DbContext();
var somethingTask = dbContext.someEntities.FirstOrDefaultAsync(e => e.Id == 1);
var morethingTask = dbContext.someEntities.FirstOrDefaultAsync(e => e.Id == 2);
await Task.WhenAll(somethingTask, morethingTask);
var something = somethingTask.Result;
var morething = morethingTask.Result;您需要确保不对多个挂起的EF操作使用相同的DbContext。
更新的,第一个代码片段实际上在EF v6.1.0中正常工作,就像预期的那样。
发布于 2014-05-26 10:59:27
关于实体框架上下文(以及其他ORMs )的问题是,它们并不是线程安全的。这意味着您不应该在多个线程之间共享同一个上下文对象,否则可能会遇到以下一些问题:
通过共享上下文,您将面临以下几个子集的问题。实际上,您应该将上下文视为当前执行计划的工作单元,这将只存储与您相关的实体和更改。当你完成所有事情后,它应该被处理掉。看一看下面的片段:
using(var ctx = new MyDbContext()){
var car = await ctx.Cars.FindAsync(id);
car.Owner = new Person{ Name = "John Doe" };
await ctx.SaveAsync();
}那么,为什么需要异步方法执行呢?因为当前执行的线程将能够执行其他任务,例如处理挂起的web请求,而不是等待数据库查询的结果,因此,继续执行最终终止的任务等等。请注意,每个线程都有开销,线程池不能使用空闲等待操作终止的线程。
由于您正在实现Web应用程序,所以您应该尝试通过web请求使用上下文,因为这是您的执行计划。也许这会让你更进一步(带服务层的存储库和UoW模式)。通常,我使用带有工厂模式和拦截器的IoC框架,但是如果希望保持简单,可以为HttpContext.Items创建一个包装器,并在请求结束时处理上下文。
https://stackoverflow.com/questions/23864098
复制相似问题