【发布时间】:2016-01-20 01:14:30
【问题描述】:
我在一个 asp.net MVC 应用程序中使用 Autofac,遇到了锁定问题。任何时候服务依赖于单例,该服务都会从根生命周期范围内解析。这是因为 Autofac:
- 从根范围解析单例组件
- 从根范围解析任何具有必须从根解析的依赖项的组件。
此外,当从任何范围解析时,Autofac 会锁定该范围。我认为这些都是很好的设计决策。我的问题是依赖于单例的行为不端的类 并且 具有缓慢的构造函数。这给需要解决单例的其他人造成了瓶颈。
由于这是在 MVC 应用程序中,每个请求都被映射到构造函数注入的某个 MVC 控制器。此外,我的大多数控制器都依赖于各种单例服务(日志记录、缓存等)。
对于具有快速构造函数的东西,这不是问题。但是一旦请求了一个写得不好的类,我的吞吐量就会下降,因为每个新请求都会被那个行为不端的构造函数阻塞。例如:
鉴于这 3 个类
//registered as SingleInstance()
class MySingleton {}
class BadTransient
{
public BadTransient(MySingleton s)
{ Thread.Sleep(5000); }
}
class FriendlyTransient {}
已解决
using(var scope = container.BeginLifetimeScope("nested scope"))
{
//resolves from child scope
var myFriend = scope.Resolve<FriendlyTransient>();
//resolves from root because it's a singleton
var singleton = scope.Resolve<MySingleton>();
//resolves from root because it has a singleton dependency.
//**** this locks the root scope for 5 seconds
//**** no one else can resolve singletons.
var troublemaker = scope.Resolve<BadTransient>();
}
有没有办法避免这个瓶颈?
显而易见的答案是拥有快速的构造函数。现实情况是,并非我的代码库中的所有构造函数都可以保证很快。有很多遗留代码,有很多代码依赖于 3rd 方代码,有些代码看起来很快,但依赖于不是的代码,有些代码通常很快,但在奇怪的情况下会崩溃等等。教育开发人员只能在一定程度上起作用。
我们一直在修复构造函数,但我需要一个更主动的解决方案。让我的用户做我的 QA 是不可接受的。
注意:我不太关心不依赖单例的慢速构造函数。他们将锁定其生命周期范围,但不会阻塞其他线程
【问题讨论】:
-
我认为 Autofac 的工作方式没有任何问题。我看到的问题在于你有一些
BadTransient类,你在构造函数中有昂贵的逻辑。我会将构造函数中的所有逻辑移至Initialize方法,该方法可由 AutofacOnActivated事件调用。所以整个初始化时间都不需要锁定作用域。 -
@nemesv 请查看我的编辑
标签: c# asp.net-mvc autofac