为什么在这个例子中使用PerThreadLifetimeManager? [英] Why is PerThreadLifetimeManager used in this example?

本文介绍了为什么在这个例子中使用PerThreadLifetimeManager?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在跟随下面的示例来设置统一以使用我的服务层。我的项目设置非常类似于本文中的一个,我了解一切,除非为什么在注册服务依赖关系时使用PerThreadLifetimeManager。请记住,我还在使用一个通用存储库和单位工作,也被用在我的服务层。大多数统一示例使用默认(瞬态)生命周期管理器,并且由于我的设置类似于下面的一个我想知道为什么我应该使用PerThreadLifeimeManager?我正在使用一个ASP.NET Web表单项目为我当前的表示层,如果这更改任何东西。

I am following the example linked to below for setting up unity to work with my service layer. My project is setup very similar to the one in this article and I understand everything except why exactly is PerThreadLifetimeManager used when registering the service dependency. Keep in mind I am also using a generic repository and unitofwork that is being used in my service layer as well. Most unity examples use the default(transient) lifetime manager, and since my setup is similar to the one below I'm wondering why I should use the PerThreadLifeimeManager? I am using an ASP.NET web forms project for my current presentation layer if that changes anything.

container.RegisterType<ICatalogService, CatalogService>(new PerThreadLifetimeManager())

存储库模式与EF代码第一依赖注入在asp.net MVC 3

推荐答案

每线程生活方式考虑有害



Per Thread Lifetime是一种非常危险的生活方式,一般来说,您应该在应用程序中使用它,特别是Web应用程序。

Per Thread Lifestyle Considered Harmful

The Per Thread Lifetime is a very dangerous lifestyle and in general you should not use it in your application, especially web applications.

这种生活方式应该被认为是危险的,因为很难预测线程的实际使用寿命。当您使用新的Thread()。Start()创建和启动一个线程时,您将获得一个新的线程静态内存块,这意味着容器将创建一个新的每线程实例为您。当使用 ThreadPool.QueueUserWorkItem 从线程池启动线程时,可能会从池中获取现有的线程。在ASP.NET中运行时也是一样。 ASP.NET池线程来提高性能。

This lifestyle should be considered dangerous, because it is very hard to predict what the actual lifespan of a thread is. When you create and start a thread using new Thread().Start(), you'll get a fresh block of thread-static memory, which means the container will create a new per-threaded instance for you. When starting threads from the thread pool using ThreadPool.QueueUserWorkItem however, you get possibly an existing thread from the pool. The same holds when running in ASP.NET. ASP.NET pools threads to increase performance.

这意味着一个线程几乎总是比一个web请求要长。另一方面,ASP.NET可以异步运行请求,这意味着可以在不同的线程处完成Web请求。当使用Per Thread生活方式时,这是一个问题。当然,这种效果在您开始使用异步/等待时会被放大。

This means that a thread will almost always outlive a web request. ASP.NET on the other hand can run requests asynchronously, which means that a web request can be finished at a different thread. And this is a problem when working with a Per Thread lifestyle. And of course this effect is amplified when you start using async/await.

这是一个问题,因为您通常会调用 Resolve< T& / code>一次在请求的开头。这将加载完整的对象图,包括使用Per Thread生活方式注册的服务。当ASP.NET在不同的线程完成请求时,这意味着解析的对象图移动到这个新线程,包括所有Per Thread注册的实例。

This is a problem since you will typically call Resolve<T> once at the beginning of the request. This will load the complete object graph including your services that are registered with the Per Thread lifestyle. When ASP.NET finishes the request at a different thread, this means that the resolved object graph moves to this new thread, including all Per Thread registered instances.

由于这些实例被注册为Per Thread,它们可能不适合在另一个线程中使用。他们几乎肯定不是线程安全的(否则他们将被注册为Singleton)。由于最初启动请求的第一个线程已经可以自由地接收新的请求,所以我们可以遇到两个线程同时访问这些Per Thread实例的情况。这将导致难以诊断和查找的竞争条件和错误。

Since these instances are registered as Per Thread, they are probably not suited to be used at another thread. They are almost certainly not thread-safe (otherwise they would be registered as Singleton). Since the first thread that initially started the request is already free to pick up new requests, we can run into the situation where two threads access those Per Thread instances simultaneously. This will lead to race conditions and bugs that are hard to diagnose and find.

所以一般来说,使用Per Thread是一个坏主意。而是使用具有明确范围(隐式或明确定义的开始和结束)的生活方式。大多数DI框架实现的每Web请求生活方式通常是隐含的范围(您不必自己结束)。

So in general, using Per Thread is a bad idea. Instead use a lifestyle that has a clear scope (an implicit or explicitly defined begin and end). The Per Web Request lifestyle that most DI frameworks implement is often implicitly scoped (you don't have to end it yourself).

为了使事情变得更糟,您引用的博客文章包含一个配置错误。 ICatalogService 使用 Per Thread 生活方式定义。然而,该服务取决于 IDALContext 服务,其被定义为瞬态。由于对 IDALContext 实例的引用作为私有字段存储在 CatalogService 中,这意味着 DALContext 只要 ICatalogService 一样生活。这是一个问题,因为 IDALContext 被定义为瞬态,并且可能不是线程安全的。

To make things worse, the blog post you referenced contains a configuration error. The ICatalogService is defined with a Per Thread lifestyle. This service however depends on an IDALContext service, which is defined as Transient. Since a reference to a IDALContext instance is stored as private field inside the CatalogService, this means the DALContext lives as long as the ICatalogService does. This is a problem because IDALContext is defined as Transient and is probably not thread-safe.

一般规则是让组件只依赖于等于或寿命更长所以瞬态可以取决于单身人士,但不能相反。

The general rule is to let components only depend on services with an equal or longer lifetime. So a Transient can depend on a Singleton but not the other way around.

由于Per Thread注册的组件通常会生活很长时间,它通常只能安全地依赖于其他Per Thread或Singleton实例。而且由于ASP.NET可以将多个线程中的单个请求分开,因此在ASP.NET应用程序(包括MVC,Web窗体,尤其是Web API)的上下文中使用Per Thread是不安全的。

Since a Per Thread registered component will typically live very long, it can typically only safely depend on other Per Thread or Singleton instances. And since ASP.NET can split a single request up in multiple threads, it is not safe to use Per Thread in the context of a ASP.NET application (both MVC, Web Forms, and especially Web API).

这篇关于为什么在这个例子中使用PerThreadLifetimeManager?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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