1

I know that the performance and speed of SimpleInjector is very good but anyway I need to figure out how big is the overhead of calling the Container.GetInstance() method.

For example if I have the following class:

public class ServiceManager
{
    private static Container _services;

    public static void Initialize()
    {
        _services = new Container();
    }

    public static ICacheClient Cache 
    {
        get
        {
            return _services.GetInstance<ICacheClient>();
        }
    }

}

what will be the performance impact if the Cache property is heavily used or I should remove it and leave the consumers to explicitly get instance of the ICacheClient using the Container directly?

Steven
  • 166,672
  • 24
  • 332
  • 435
Ruslan Kiskinov
  • 916
  • 7
  • 4
  • How fast is this in your own benchmarks? – Steven Jul 24 '13 at 13:43
  • 1
    Besides, your example and explanation seems strange. Why do you create a new container inside one of your components? You should usually have [only one container](https://simpleinjector.codeplex.com/wikipage?title=Using%20the%20Simple%20Injector#The-Container) that you create in the startup path of your application, and you should [not let components ask for things directly](http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/) from the container (but you should use dependency injection to build object graphs). – Steven Jul 24 '13 at 13:52

1 Answers1

2

Nobody can answer that question for you. The performance impact depends on lots of variables such as your hardware, your application, and how often that property is being called.

So the real question is, is it fast enough for your situation. You are the only one who can find out by benchmarking this.

The framework is highly optimized in that it will:

  • Minimize the number of method calls in the happy path of the framework (which means the minimum number of method calls when calling GetInstance<T> and GetInstance(Type)).
  • Minimize the number of locks in the happy path of the application (the happy path is currently lock-free).
  • Minimize the number of callbacks into the container when resolving an object graph (which means that the container itself will not call GetInstance<T> to resolve an object's dependencies, but will inline the creation of those dependencies in the registration's internally constructed Func<object> delegate).

But although Simple Injector is highly optimized, there is a constant cost in calling GetInstance<T>. On each call, the container will always have to:

  • Do a dictionary lookup (using a Dictionary<Type, InstanceProducer> in the current implementation) for the given typeof(T).
  • Call the GetInstance() method on the found InstanceProducer instance.
  • Call a Func<object> delegate for the creation the given instance (inside the InstanceProducer.GetInstance method).
  • Do a cast from object to T before returning from GetInstance<T>.

From this constant cost, doing the dictionary lookup takes about 80% the time. The percentage of the constant overhead however goes down rather quickly when you start resolving anything else than a singleton, especially when resolving big object graphs.

Still, if you're doing lots of calls to the Cache property in a performance critical path of the application, you might want to optimize that (but again, you have to determine whether it is too slow: don't do premature optimizations). One easy way to do this is by injecting the ICacheClient into the constructor of consumers. This prevents the instance from being resolved from the container over and over again, and allows consumers to just use the locally cached ICacheClient instance without a problem.

As a matter of fact, this is a general pattern called Constructor Injection and is an adviced practive. Prefer letting the container build up a complete object graph for you (by using constructor injection) by making one single call to GetInstance<T> at the start of a 'request', instead of calling back constantly to the container during that request.

Steven
  • 166,672
  • 24
  • 332
  • 435