A co-worker sent me an article, IoC Battle in 2015..., comparing the speed differences between several IoC containers. It's a topic that comes up every once in a while. This usually happens when developers are debating which container is best. I'm a big fan of dependency injection, so I was interested to see the results.
I Ran It And Then...
I saw the results, and forked the linked repository. My first run of the benchmark app produced results similar to the article:
I dug into the code, wanting to see what was up with Windsor. The registration code was really funky. Each component was registered in a separate registration call. Regular users of Windsor know this isn't the right way to do this.
The old registrations looked like this;
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
_container.Register(Component.For<IRepository>().ImplementedBy<Repository>().LifeStyle.Is(lifestyle)); | |
_container.Register( | |
Component.For<IAuthenticationService>().ImplementedBy<AuthenticationService>().LifeStyle.Is(lifestyle)); | |
_container.Register(Component.For<UserController>().ImplementedBy<UserController>().LifeStyle.Is(lifestyle)); | |
_container.Register(Component.For<IWebService>().ImplementedBy<WebService>().LifeStyle.Is(lifestyle)); | |
_container.Register(Component.For<IAuthenticator>().ImplementedBy<Authenticator>().LifeStyle.Is(lifestyle)); | |
_container.Register(Component.For<IStockQuote>().ImplementedBy<StockQuote>().LifeStyle.Is(lifestyle)); | |
_container.Register(Component.For<IDatabase>().ImplementedBy<Database>().LifeStyle.Is(lifestyle)); | |
_container.Register(Component.For<IErrorHandler>().ImplementedBy<ErrorHandler>().LifeStyle.Is(lifestyle)); | |
_container.Register(Component.For<IService1>().ImplementedBy<Service1>().LifeStyle.Is(lifestyle)); | |
_container.Register(Component.For<IService2>().ImplementedBy<Service2>().LifeStyle.Is(lifestyle)); | |
_container.Register(Component.For<IService3>().ImplementedBy<Service3>().LifeStyle.Is(lifestyle)); | |
_container.Register(Component.For<IService4>().ImplementedBy<Service4>().LifeStyle.Is(lifestyle)); | |
_container.Register(Component.For<ILogger>().ImplementedBy<Logger>().LifeStyle.Is(lifestyle)); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
container.Register( | |
Component.For<IRepository>().ImplementedBy<Repository>().LifestyleSingleton(), | |
Component.For<IAuthenticationService>().ImplementedBy<AuthenticationService>().LifestyleSingleton(), | |
Component.For<UserController>().ImplementedBy<UserController>().LifestyleSingleton(), | |
Component.For<IWebService>().ImplementedBy<WebService>().LifestyleSingleton(), | |
Component.For<IAuthenticator>().ImplementedBy<Authenticator>().LifestyleSingleton(), | |
Component.For<IStockQuote>().ImplementedBy<StockQuote>().LifestyleSingleton(), | |
Component.For<IDatabase>().ImplementedBy<Database>().LifestyleSingleton(), | |
Component.For<IErrorHandler>().ImplementedBy<ErrorHandler>().LifestyleSingleton(), | |
Component.For<IService1>().ImplementedBy<Service1>().LifestyleSingleton(), | |
Component.For<IService2>().ImplementedBy<Service2>().LifestyleSingleton(), | |
Component.For<IService3>().ImplementedBy<Service3>().LifestyleSingleton(), | |
Component.For<IService4>().ImplementedBy<Service4>().LifestyleSingleton(), | |
Component.For<ILogger>().ImplementedBy<Logger>().LifestyleSingleton() | |
); |
My Thoughts
It's important to use something correctly when doing benchmarks.
Different containers run at different speeds. The resolutions were for 1 million "web services" each which had fairly deep object graphs. So, yeah, it took Windsor some 30 seconds to do this. But then, it's unlikely a single app will be doing that. When you hit that performance demand, it's time to start scaling horizontally (more on that some other time).
In a Nutshell
Donald Knuth is quoted as having written, "The real problem is that programmers have spent far too much time worrying about efficiency in the wrong places and at the wrong times; premature optimization is the root of all evil (or at least most of it) in programming." If you're at the point you're worried about how fast resolving 1M object graphs is, then it's a problem. Until then, use the container that works for you.
I put my fork of this project on GitHub.