Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DynamicProxy Generation Speed

I'm trying to troubleshoot some startup time concerns. After doing some profiling, I've found the main culprit is ClassProxyGenerator.GenerateCode. This takes 400-600ms per type the first time. So if the entry point to the application has 8 dependencies (in a chain) which need proxies generated, the startup time of the application goes up by 4.8 seconds. This might not seem like a lot, but to a user, it seems like ages.

Any advice for improving this?

Update:

I can reproduce the time with the following console application:

        var container = new WindsorContainer();
        container.Register(Component.For<Interceptor>()); // dummy IInterceptor...does nothing
        container.Register(Component.For<IMyRepository, MyAbstractRepository>().Interceptors<Interceptor>());
        var t = DateTime.Now;
        var instance = container.Resolve<IMyRepository>();
        Debug.WriteLine("Resolved in " + (DateTime.Now - t).TotalMilliseconds);

Outputs somewhere between 550ms and 750ms.

IMyRepository is a repository interface for 30 entity types (generated by a T4 template). It has 31 IQueryables, 31 Save overloads, and 31 Delete overloads. MyAbstractRepository is a partial abstract class. It declares the same 3 x 31 methods.

If I remove all the save and delete methods and leave just the 31 IQueryables AND don't register the abstract repository

  container.Register(Component.For<IMyRepository>().Interceptors<Interceptor>());

I still run around 250ms for the initial generation.

This is a very (very very) fast machine...so anything in the real world will likely perform slower than the numbers listed above.

like image 921
Jeff Avatar asked Nov 13 '22 17:11

Jeff


1 Answers

You might be able to perform the proxy initialization in a different thread, so that the application itself can continue to initialize while the proxies are generated. Consider queuing this into the threadpool.

Another option might be to compile the proxies into a persisted assembly file, which is then saved to disk. Doing this would significantly lower the startup time after the first run.

I'm not sure why Castle's dynamic proxies take so long to initialize. I don't use them, I usually emit code directly (either as LCG for simple methods, and via full Reflection.Emit for complete implementations). I never had such long delays, even when generating hundreds of LCG methods. Maybe using a different approach/library (LinFu etc.) might fix the issue as well.

like image 192
Lucero Avatar answered Dec 15 '22 20:12

Lucero