Autofac resolving a singleton creates a bottleneck

做~自己de王妃 提交于 2019-12-04 04:03:14

I agree with @nemesv that object construction should be fast, but this also means not initializing in OnActivated. Rather, you should do this lazily when the component is first used. For instance by implementing a proxy or some Lazy<T> internally.

But if you have an application with rather extreme throughput and concurrency characteristics and you verified through performance profiling that locking is a bottleneck, you could consider switching to a lock-free IoC container.

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!

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();
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!