Autofac解决单身造成瓶颈 [英] Autofac resolving a singleton creates a bottleneck

查看:147
本文介绍了Autofac解决单身造成瓶颈的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在一个asp.net MVC应用程序使用Autofac和锁定跨越问题就来了。每当一个服务依赖于一个单身,该服务是从根寿命范围内解决。这是因为Autofac:

I'm using Autofac in an asp.net MVC app and came across a problem with locking. Anytime a service depends on a singleton, that service is resolved from the root lifetime scope. This is because Autofac:


  • 解析从根范围
  • 单组分
  • 从根范围内谁有依赖,必须从根本解决解决任何组件。

此外,从任意范围解析时,Autofac锁定该范围。我觉得这些都是细小的设计决策。我的问题是与谁依靠单身有缓慢的构造行为不端类。这些创建一个瓶颈别人需要解决一个单身。

Further, when resolving from any scope, Autofac locks that scope. I think these are fine design decisions. My problem is with misbehaving classes who depend on singletons and have slow constructors. These create a bottleneck for anyone else needing to resolve a singleton.

由于这是一个MVC应用程序,每个请求都得到映射到一些MVC控制器的构造函数注入。此外,我的大部分控制器采取不同的单服务(日志,缓存等)的依赖。

Since this is in a MVC app, each request is getting mapped to some MVC controller that's constructor injected. Further, most of my controllers take dependencies on various singleton services (logging, caching, etc).

有关的东西快速构造,这是没有问题的。但是,只要一个写得不好类的要求,我吞吐量坦克,因为每一个新的请求被阻止上行为不端的构造。例如:

For things with fast constructors this is not a problem. But as soon as one poorly written class is requested, my throughput tanks because every new request is blocked on that misbehaving constructor. For example:

考虑到这些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>();         
}

有没有一种方法可以让我避免这种瓶颈?

答案显然是具有快速构造函数。现实情况是,并非所有在我的codeBase类构造函数可以保证要快。还有的很多传统code的的,还有很多code,它依赖于第三方code的,有code,看起来快,但依赖于code,它是不是,有code,它通常是快,​​但在奇数的情况下发生故障,教育等开发商只能在一定程度上。

The obvious answer is to have fast constructors. The reality is that not all the constructors in my codebase can be guaranteed to be fast. There's a lot of legacy code, there's lots of code that relies on 3rd party code, there's code that looks fast but depends on code that isn't, there's code that's usually fast but breaks down in odd circumstances, etc. Educating developers only works to a certain extent.

我们一直在固定的构造,因为我们找到他们,但我需要更积极主动的解决方案。这是不能接受的,让我的用户做我的QA。

We've been fixing constructors as we find them, but I need a more proactive solution. It's not acceptable to let my users do my QA.

注:我不在乎尽可能多的关于不依赖于一个单身缓慢的构造函数。他们将锁定其使用寿命范围内,但它不会阻止其他线程

推荐答案

我固定通过重新注册使用autofac的闭包语法的所有单身的问题。结果
这使建筑逻辑autofac,但是从孩子一生范围解决单身。从本质上说:

I fixed the problem by re-registering all the singletons using autofac's closure syntax.
This keeps construction logic in autofac, but resolves singletons from a child lifetime scope. In essence:

builder.Register<MySingleton>().AsSelf().AsImplementedInterfaces();
//.. other registrations

var container = builder.Build();

// now resolve each singleton, forcing all to be constructed if not already
//   and then register the instance
var builder2 = new ContainerBuilder();

var mySingleton = container.Resolve<MySingleton>();
builder2.Register(c => mySingleton).AsSelf().AsImplementedInterfaces();
builder2.Update(container);

//.....
var scope = container.BeginLifetimeScope("child scope");   
scope.Resolve<MySingleton>(); //not resolved from root!

然后,因为有许多单身人士,我可以编程方式查询自己的类型,我写了一个函数,它的类型列表,并运行上述code。它做了一点思考巫术,虽然只是在正常autofac注册code月底在应用程序启动运行。

Then, since there are many singletons and I can query their types programmatically, I wrote a function that takes a list of types and runs the above code. It has to do a little reflection wizardry, though only runs at app startup at the end of the normal autofac registration code.

void ReRegisterSingletons(IContainer container, List<Type> singletonTypes)
{
     var builder= new ContainerBuilder();
     foreach(var type in singletonTypes)
     {

          var resolved = container.Resolve(type);
          var method = this.GetType().GetMethod("ReRegister").MakeGenericMethod(new []{type});
          method.Invoke(this, new []{resolved});
     }

     builder.Update(container);
}

void Register<T>(ContainerBuilder builder, object singleton)
{
    var theObj = (T)singleton;

     //a typed lambda was the only way I could get both the class name and the interface names to resolve from the child scope. RegisterInstance still resolves from root, and the non-generic lamba register can resolve the class name from child scope but not the interface names...
    builder.Register(c => theObj).AsSelf().AsImplementedInterfaces();
}

这篇关于Autofac解决单身造成瓶颈的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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