何时使用 PerThreadLifetimeManager? [英] When to use PerThreadLifetimeManager?

本文介绍了何时使用 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 unit of work 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())

[asp.net MVC 3中EF代码优先依赖注入的repository模式][1][1]:http://www.dotnetage.com/publishing/home/2011/07/05/6883/the-repository-pattern-with-ef-code-first-dependeny-injection-in-asp-net-mvc3.html

[The repository pattern with EF code first dependency injection in asp.net MVC 3][1] [1]: http://www.dotnetage.com/publishing/home/2011/07/05/6883/the-repository-pattern-with-ef-code-first-dependeny-injection-in-asp-net-mvc3.html

推荐答案

每线程生命周期是一种非常危险的生活方式,一般来说,您不应该在您的应用程序中使用它,尤其是 Web 应用程序.

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

这种生活方式应该被认为是危险的,因为很难预测线程的实际寿命是多少.当您使用 new 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 生活方式时,这是一个问题.当然,当您开始使用 async/await 时,这种效果会被放大.

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.这将加载完整的对象图,包括使用 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,它们可能不适合在另一个线程中使用.它们几乎肯定不是线程安全的(否则它们将被注册为单例).由于最初启动请求的第一个线程已经可以自由地接收新请求,因此您可能会遇到两个线程同时访问这些 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, you 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.

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

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 服务,该服务被定义为 Transient.由于对 IDALContext 实例的引用作为私有字段存储在 CatalogService 中,这意味着 DALContextICatalogService 一样存在 确实如此.这是一个问题,因为 IDALContext 被定义为 Transient 并且可能不是线程安全的.

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天全站免登陆