实体框架:如何防止 dbcontext 被多个线程访问?

Posted

技术标签:

【中文标题】实体框架:如何防止 dbcontext 被多个线程访问?【英文标题】:Entity Framework: How to prevent dbcontext getting accessed by multiple threads? 【发布时间】:2016-10-29 10:52:55 【问题描述】:

我正在使用异步并等待多线程。

如果我在单个线程上使用 Async 并等待它可以正常工作,但是当我使用多个线程时,它会因我尝试使用多个线程访问 dbcontext 的错误而中断。

我知道我做不到。但现在我想要一个调度程序,它将调度对每个线程的 dbcontext 访问。

我如何编写这种调度程序/互斥锁或任何解决此问题的方法。

【问题讨论】:

您是否正在从不同的线程访问 same DbContext 你能附上你的代码吗?也许你忘了添加configureawait(false) 来捕获上下文 是的,Fedeico Dipuma Aiska Hendra,我也更新了代码 【参考方案1】:

您绝对可以将 EF 与 async/await 一起使用,但 you can't perform two operations at once on the same context。

就性能而言,it's actually faster to create two contexts 这似乎是您使用async/await 的原因。

对于本示例,我建议为每个 CallToDbOps() 创建两个单独的上下文。

【讨论】:

如果您查看我的代码,我正在创建另一个数据库上下文实例,但仍然出现相同的错误。我现在很困惑 在前一个异步操作完成之前在此上下文上启动了第二个操作。使用 'await' 确保在此上下文中调用另一个方法之前所有异步操作都已完成。不保证任何实例成员都是线程安全的。 您应该将awaitWait() 添加到var v = dbo.GetMutualFund();。您使用线程与使用 TPL 有什么原因吗?而不是new Thread(),我会看看Task.Run()。然后您的 CallToDbOps 方法也可以正确异步。 这很有帮助,但并没有解决问题,谢谢【参考方案2】:

这与其说是一个答案,不如说是帮助[用户]的信息......

Have a read of this blog 还有have a read of this article about Entity Framework specifications for its async pattern support

DbContext 不是线程安全的

您绝不能同时从多个线程访问您的 DbContext 派生实例。这可能会导致通过同一数据库连接同时发送多个查询。它还会破坏 DbContext 维护的一级缓存,以提供其身份映射、更改跟踪和工作单元功能。

在多线程应用程序中,您必须在每个线程中创建和使用 DbContext 派生类的单独实例。

如果 DbContext 不是线程安全的,它如何支持 EF6 引入的异步查询功能?只需防止在任何给定时间执行多个异步操作(如实体框架规范中记录的异步模式支持)。如果您尝试在同一个 DbContext 实例上并行执行多个操作,例如通过 DbSet.ToListAsync() 方法并行启动多个 SELECT 查询,您将收到带有以下消息的 NotSupportedException:

在前一个异步操作完成之前,在此上下文上启动了第二个操作。使用 'await' 确保在此上下文中调用另一个方法之前所有异步操作都已完成。不保证任何实例成员都是线程安全的。

Entity Framework 的异步功能用于支持异步编程模型,而不是启用并行性。

摘自英孚文章:

"线程安全

虽然线程安全会使异步更有用,但它是一个正交特性。鉴于 EF 与由用户代码组成的图形交互以维护状态并且没有简单的方法来确保此代码也是线程安全的,因此尚不清楚我们是否可以在最一般的情况下实现对它的支持。

目前,EF 会检测开发人员是否尝试同时执行两个异步操作并抛出异常。"

【讨论】:

这是否意味着我不能在 EF 中使用多线程?我需要停止使用 EF 吗? 如何使用 await?我在任何地方都使用了等待,但它仍然要求上下文正在与多个线程一起使用 EF6+ 中异步的问题是每个线程在触发查询之前必须等待其他线程,即它们不能并行工作,它们必须相互等待......对于多线程来说似乎适得其反应用程序相互等待,但这就是 EF6+ 必须的方式......就我个人而言,我倾向于以工作单元模式来做所有事情。 我可以看看一些代码吗?我正在尝试编写那个等待的东西,但我仍然无法做到。如果你能看一下,我已经添加了一些代码 对不起,我很忙,很快就要上线一些代码...最后一篇文章为您指明了正确的方向... EF6 尝试将 async / await 实现为基本格式.. . 根据 vs 2012 ...msdn.microsoft.com/en-us/library/hh191443(v=vs.110) 了解 await 以及它实际上如何不等待而是加入执行线程并在最后标记它,然后返回到异步调用。

以上是关于实体框架:如何防止 dbcontext 被多个线程访问?的主要内容,如果未能解决你的问题,请参考以下文章

实体框架核心和多线程

如何从DbContext中清除未插入的POCO? - 实体框架代码优先

集成测试共享数据库的多个实体框架 dbcontexts

具有多个 MySql 模式的实体框架多个 DbContext

使用实体框架6的mvc4中的单个或多个DbContext文件

C# 实体框架 DBContext