【发布时间】:2013-11-03 15:07:00
【问题描述】:
刚刚开始测试 EF6 及其异步功能。 当我意识到它们不是线程安全的时,我很惊讶。我有点假设这就是重点。
多年来,我已经拥有自己的基于 Task 的扩展方法,但我一直在等待 EF 让它们成为线程安全的。
至少我的基于任务的功能locked 不会相互干扰。 EF6 甚至没有走那么远。但主要问题是我的代码与他们的代码共享。即尝试发出异步查询,然后在它完成之前尝试访问触发延迟加载的导航属性(在同一上下文中预加载的完全独立的实体上)。这可以由 UI 触发,也可以由即时函数之外的其他代码触发,也可以由许多其他场景触发。
据我所知。 dbContext 中仅有的两个共享(实体之间)可变资源是连接和更改跟踪(缓存)。如果我们可以在这些功能周围添加锁定,那么我们将拥有一个线程安全的上下文。
我们甚至可以分两个阶段完成。如果我们可以实现一个提供者来锁定用于查询数据库的一个集中功能。然后任何未跟踪的查询 - 通过返回非实体(匿名)对象或通过调用 AsNoTracking() - 将是线程安全的,并且即使在另一个线程可能要求延迟加载的对象时也可以安全地使用 Async 函数调用。
我们的可扩展性不会比现在更糟,因为我们现在必须为每个线程使用一个上下文,如果您尝试跳过甚至一个 await 以引入一些并行性或正在工作,即使是 Async 函数也不适用在事件系统(如 wpf)中,一旦等待的函数与任务一起返回,可能会触发。
所以我的问题是。有没有人实现过这样的提供者。或者有人愿意和我一起工作吗?
【问题讨论】:
-
有趣的是,EF6 不仅线程不安全,而且是线程化的。 EF6 和
Async函数的重点不是线程。其实asyncawait不是线程框架。它是一个async框架。您可以编写单线程异步应用程序,实际上这是您在node.js中唯一可以做的事情。 -
我相信使用 EF6
async时的一般指导是完全禁用延迟加载。否则,您将混合使用异步代码和阻塞代码,这将始终存在行为怪癖。 -
@StephenCleary 由于当前的实施,这可能是一般指导。但是,如果有人要在
locked 围绕数据库访问的提供商上工作。然后我们就可以同时使用两者了。 -
@Rabbi:关键是你不会想要。延迟加载将不必要地阻塞异步操作上的线程。如果您
Include相关实体或执行单独的(异步)后续请求,您的代码将完全异步。 -
@Rabbi:大部分时间异步
Tasks 是基于(逻辑)事件,not 线程。在 EF6 中尤其如此。
标签: multithreading entity-framework task-parallel-library entity-framework-6