首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >EF6异步方法混淆

EF6异步方法混淆
EN

Stack Overflow用户
提问于 2014-05-26 06:36:28
回答 2查看 2K关注 0票数 2

最近,我们升级到EF6跳转,以利用webapi控制器中的异步调用,但经过一些在线阅读,我可以知道。

代码语言:javascript
复制
- 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.

https://entityframework.codeplex.com/wikipage?title=Task-based%20Asynchronous%20Pattern%20support%20in%20EF

但在这个问题中,EF数据上下文-异步/等待和多线程也表达了同样的观点

但是,当我查看来自MS http://msdn.microsoft.com/en-us/data/jj819165.aspx的示例时,我感到困惑,因为如果我查看堆栈溢出问题中提供的答案,那么我们目前似乎没有任何解决方案/模式来实现它--使用单个db上下文来实现线程安全?

所以我的问题是如何实现

代码语言:javascript
复制
var dbContext = new DbContext();
var something = await dbContext.someEntities.FirstOrDefaultAsync(e => e.Id == 1);
var morething = await dbContext.someEntities.FirstOrDefaultAsync(e => e.Id == 2);

线程安全功能是正确的吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-05-26 06:47:15

你引用的相同的EF文档

目前,EF将检测开发人员是否试图一次执行两个异步操作并抛出。

因此,即使在await之后有一个线程开关,这段代码也可以工作,因为它仍然是按顺序执行的:

代码语言:javascript
复制
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错误。

另一方面,以下代码很可能会失败,因为我们引入了并行性:

代码语言:javascript
复制
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中正常工作,就像预期的那样。

票数 2
EN

Stack Overflow用户

发布于 2014-05-26 10:59:27

关于实体框架上下文(以及其他ORMs )的问题是,它们并不是线程安全的。这意味着您不应该在多个线程之间共享同一个上下文对象,否则可能会遇到以下一些问题:

  • 数据库中未提交的实体将在多个执行计划之间共享;
  • 上下文抛出的异常,使使用该上下文的每个线程无效,您将如何处理这些问题;
  • 由于不知道何时应该释放上下文而可能发生的内存泄漏(有人还在使用上下文吗?)

通过共享上下文,您将面临以下几个子集的问题。实际上,您应该将上下文视为当前执行计划的工作单元,这将只存储与您相关的实体和更改。当你完成所有事情后,它应该被处理掉。看一看下面的片段:

代码语言:javascript
复制
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创建一个包装器,并在请求结束时处理上下文。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23864098

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档