线程安全实体框架6 [英] Thread safe Entity Framework 6

查看:87
本文介绍了线程安全实体框架6的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

只需开始测试EF6及其异步功能即可. 当我意识到它们不是线程安全的时,我感到很惊讶.我有点以为这就是重点.

多年以来,我已经拥有了自己的基于Task的扩展方法,但是我一直在期待着EF的发展,那就是使它们具有线程安全性.

至少我的基于任务的功能lock设置为互不干扰. EF6甚至没有走那么远.但是主要的问题是我的代码与他们的代码共享.即尝试发出异步查询,然后在完成查询之前尝试访问导航属性(在同一上下文中的预加载的完全独立实体上),从而触发延迟加载.这可以由UI触发,也可以由即时功能之外的其他代码触发,也可以由许多其他情况触发.

据我所知. dbContext中仅有的两个共享的(实体之间)可变资源是连接和更改跟踪(缓存).如果我们可以在功能周围添加锁定,那么我们将拥有线程安全上下文.

我们甚至可以分两个阶段进行.如果我们可以实现一个提供者,该提供者锁定了用于查询数据库的一个集中式功能.然后,任何非跟踪查询(通过返回非实体(匿名)对象或通过调用AsNoTracking())都是线程安全的,并且即使在另一个线程可能要求延迟加载对象的情况下,也可以安全地使用Async函数进行调用. /p>

我们的可伸缩性不会再差那么一点,现在我们必须在每个线程中使用一个上下文,如果您尝试跳过甚至等待引入一些并行性或正在运行的代码,那么甚至Async函数都将无法使用.在事件系统(如wpf)中,一旦等待的函数随任务返回,该系统可能会触发.

所以我的问题是.有没有人实现这样的提供者.还是有人愿意与我合作?

解决方案

我认为您正面临体系结构问题.您所描述的是UI直接使用EF对象的应用程序,它打破了关注点分离"范例.

在我这边,我在Model层上使用海关线程安全的缓存,让所有事情都在Model层上进行.我使用众所周知的AsyncLock在缓存中实现了线程安全性.

DbContext对象以及与EF CRUD相关的每个操作的生存期都非常有限.每个CRUD操作实例化它自己的DbContext,并将模型对象返回到缓存,然后,上下文被垃圾回收.我的应用程序使用缓存作为抽象层,而缓存使用EF作为数据库抽象层.

例如,通过在模型层上实现自定义方法来探索对象上的附加属性,该方法将对象ID作为参数,并将相关对象的列表返回到缓存. UI询问缓存,然后缓存询问EF,然后在可用时,对缓存的调用将对象返回到UI.就这么简单.

EntityFramework并非设计为线程安全的,因此无法以多线程方式使用它. (EF线程安全)

您不必构建对DbContext的并行访问,而必须构建一个可以以多线程方式访问的Model层.您的模型可以对数据库进行多个并行调用,但请记住,每个调用都必须实例化并保留其自己的DbContext.在每次调用结束时,必须处理相关的DbContext.

DbContext的实例化速度非常快,唯一的缺点是网络延迟.这就是为什么内存缓存是个好主意的原因.

Just starting testing EF6 and its Async functions. Boy was I surprised when I realized that they are not thread safe. I kinda assumed that that was the point.

I had my own Task based extension methods for years already, but what I was waiting for from EF was to make them thread safe.

At least my Task based functions locked as to not interfere with each other. EF6 doesn't even go that far. But the main problem is something that my code shares with theirs. i.e. Try issuing an async query and then before it completes try accessing a navigation property (on a pre-loaded totally separate entity in the same context) which triggers lazy loading. This could be triggered either by the UI, or by other code outside of the immediate function, or by a dozen other scenarios.

As far as I can tell. The only two shared (between entities) mutable resources in a dbContext are the connection and change tracking (caching). If we could add locking around those to functionalities then we would have a thread safe context.

We could even do it in two stages. If we could implement a provider that locked the one centralized function used to query the database. Then any non tracked queries - either by returning non entity (anonymous) objects or by calling AsNoTracking() - would be thread safe, and would be safe to call with Async functions even when another thread might be asking for a lazy loaded object.

Our scaleability would be no worse off then we are now that we have to use one context per thread, and even the Async functions are off the table if you try to skip even one await to introduce a bit of parallelism or are working in an evented system (like wpf) that might trigger once the awaited function returns with the task.

So my question is. Has anyone implemented a provider like this. Or would anyone be willing to work with me on it?

解决方案

I think you are facing an architectural issue. What you describes is an application where UI directly uses EF objects, and it breaks the "separation of concerns" paradigm.

On my side, I use customs thread-safe caches on a Model layer, letting everything happens on the Model layer. I implemented thread-safety on my cache with the well-known AsyncLock.

DbContext objects, and every EF CRUD related operations have a very limited lifetime. Each CRUD Operation instantiate it's own DbContext, and returns Model Objects to the cache, then, contexts are garbage collected. My applications uses caches as an abstraction layer, and caches uses EF as a DB abstraction layer.

For example, exploring attached properties on Objects, is done by implementing custom methods on the Model layer, which takes the object Id as parameter, and returns a list of related objects to the cache. The UI asks the Cache, then the Cache asks EF, then once available, the call made to the cache returns objects to the UI. Simple as that.

EntityFramework is not designed to be thread safe, so there's no way to work with it in a multi-threaded way. (EF thread safety)

Instead of having parallel access to you DbContext, you have to build a Model layer which can be accessed in a multi-threaded way. And your model can make multiple parallel calls to you DB, but keep in mind that each call must instantiate and keep it's own DbContext. At the end of each call, the related DbContext must be disposed.

DbContext are really fast to instantiate, the only downside is the network latency. That's why a memory cache is a good idea.

这篇关于线程安全实体框架6的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆