Hiro vs其他IoC容器

12 .net performance ioc-container inversion-of-control

本文中(2009年4月11日),作者声称Hiro是:

"世界上最快的IOC容器......一个静态预编译的IOC容器,其运行速度与没有IOC容器的应用程序一样快".

它仍然是今天最快的IOC容器吗?它准备好生产吗?在编译时有没有其他容器可以做IOC?与其他IOC容器相比,它的主要优点和缺点是什么?

谢谢

Ste*_*ven 20

Hiro声称是最快的容器.该声明基于作者给出的基准(有关许多容器之间的客观比较,请参见此处).此基准测试是否切合实际取决于应用程序的大小.基准测试似乎是用一小组注册类型巧妙地设置的.在向基准测试添加更多注册时,性能开始下降(请参阅下面的示例基准).仔细观察我们可以看出Hiro具有O(n)的性能特征,而普通DI框架具有O(1)的特征,因此对于其他框架,性能与注册类型的数量保持不变.

Hiro的好处是它可以动态生成一个新的程序集,解析一个新类型只包含一个接口调用.这非常快.另一方面,最常见的DI框架在调用GetInstance期间总是必须进行字典查找.Hiro的GetInstance方法在内部基本上是一个大的switch case语句,实现为一堆if语句.基于if的switch case语句非常快,直到某一点.C#编译器使用(我相信)18个案例语句的启发式作为转折点.在该数字下面,编译器生成一堆if语句.在该数字之上,它创建并存储静态字典并进行字典查找,因为如果只是更快,则查找字典查找的性能.

好吧猜猜看; Hiro不像C#编译器那样使用优化.这就是随着越来越多的类型被添加到容器中,性能不断下降的原因.线性性能特征 - 或简称O(n)对于小型数据集是可以的,但是任何编写良好且通常大小,依赖性友好的应用程序都具有许多类型注册/映射.在那种情况下,Hiro的表现迅速下降.

那么,回答你的问题:

它仍然是今天最快的IOC容器吗?

对于非常小的应用程序,它是最快的.对于任何正常大小的应用程序,它从来都不是最快的.

它准备好生产吗?

很难说.它目前的状态是alpha,它错过了其他IOC框架所具有的许多功能.开发人员(见下面的评论)发布了稳定的版本.这意味着根据开发人员的说法,它已准备好投入生产.

与其他IOC容器相比,它的主要优点和缺点是什么?

看一下本文(以及后续内容),它给出了IOC框架的一个很好的(特征)比较.这篇文章的作者对他认为重要的事物抱有一种看法.你必须为自己制作这样的清单.您的列表中的性能似乎很高.但请注意,还有其他方法可以提高性能.例如,通过将类型注册为单例来防止创建许多类型.

这是与其他容器的一点比较.请注意,我没有写Hiro,所以我可能会遗漏一些东西,特别是因为似乎根本没有文档,但是这里有:

  1. 您需要运行4个程序集,而不是大多数IOC框架的1或2个程序集.
  2. 当解析递归依赖时,它会抛出堆栈溢出(大多数框架执行此操作).所以没有循环依赖检测.
  3. 似乎不支持除瞬态之外的任何生活方式(作者确实会说它,但我目前看不到支持).这实际上对性能不利,因为大多数服务通常都会注册为单例.据作者说,它支持多种生活方式.
  4. 不支持解析开放泛型类型.
  5. 不支持未注册的类型解析.
  6. 我没有文档接受XML(intellisense)文档.

在编译时有没有其他容器可以做IOC?

定义'编译时间'.Hiro在运行时动态生成一个新的程序集.其他人(如Autofac,WindsorSimple Injector)发布IL或编译代表.这并不比一次编译完整的程序集慢(但是,调用委托的开销比调用接口调用要慢一点).

顺便说一句,我更改了基准测试以查看上述行为.注册了50种额外类型,你会发现Hiro的速度已经是初始基准的三倍.这是我使用的代码:

public interface IHandler<T> { }

public class Handler<T> : IHandler<T> { }

public class HiroUseCase : UseCase
{
    IMicroContainer container;

    private static void RegisterHandler<T>(DependencyMap map)
    {
        map.AddService(typeof(IHandler<T>), typeof(Handler<T>));
    }       

    public HiroUseCase()
    {
        var map = new DependencyMap();

        // *** My added registrations
        RegisterHandler<byte>(map);
        RegisterHandler<byte?>(map);
        RegisterHandler<short>(map);
        RegisterHandler<short?>(map);
        RegisterHandler<ushort>(map);
        RegisterHandler<ushort?>(map);
        RegisterHandler<int>(map);
        RegisterHandler<int?>(map);
        RegisterHandler<uint>(map);
        RegisterHandler<uint?>(map);

        RegisterHandler<long>(map);
        RegisterHandler<long?>(map);
        RegisterHandler<ulong>(map);
        RegisterHandler<ulong?>(map);
        RegisterHandler<float>(map);
        RegisterHandler<float?>(map);
        RegisterHandler<double>(map);
        RegisterHandler<double?>(map);
        RegisterHandler<decimal>(map);
        RegisterHandler<decimal?>(map);

        RegisterHandler<DateTime>(map);
        RegisterHandler<DateTime?>(map);
        RegisterHandler<char>(map);
        RegisterHandler<char?>(map);
        RegisterHandler<object>(map);
        RegisterHandler<string>(map);
        RegisterHandler<bool>(map);
        RegisterHandler<bool?>(map);
        RegisterHandler<Enum>(map);
        RegisterHandler<DateTimeKind>(map);

        RegisterHandler<DateTimeKind?>(map);
        RegisterHandler<DateTimeOffset>(map);
        RegisterHandler<DateTimeOffset?>(map);
        RegisterHandler<DayOfWeek>(map);
        RegisterHandler<DayOfWeek?>(map);
        RegisterHandler<DBNull>(map);
        RegisterHandler<Delegate>(map);
        RegisterHandler<DivideByZeroException>(map);
        RegisterHandler<DllNotFoundException>(map);
        RegisterHandler<Exception>(map);

        RegisterHandler<KeyNotFoundException>(map);
        RegisterHandler<InvalidOperationException>(map);
        RegisterHandler<InvalidCastException>(map);
        RegisterHandler<InvalidProgramException>(map);
        RegisterHandler<InvalidTimeZoneException>(map);
        RegisterHandler<IDisposable>(map);
        RegisterHandler<IComparable>(map);
        RegisterHandler<IEquatable<int>>(map);
        RegisterHandler<IEnumerable>(map);
        RegisterHandler<IEqualityComparer>(map);

        // *** Original benchmark setup
        map.AddService(typeof(IWebApp), typeof(WebApp));
        map.AddService(typeof(IAuthenticator), typeof(Authenticator));
        map.AddService(typeof(IStockQuote), typeof(StockQuote));
        map.AddService(typeof(IDatabase), typeof(Database));
        map.AddService(typeof(IErrorHandler), typeof(ErrorHandler));
        map.AddService(typeof(ILogger), typeof(Logger));

        IContainerCompiler compiler = new ContainerCompiler();
        var assembly = compiler.Compile(map);;

        var loadedAssembly = assembly.ToAssembly();
        var containerType = loadedAssembly.GetTypes()[0];
        container = (IMicroContainer)Activator
            .CreateInstance(containerType);
    }

    public override void Run()
    {
        var webApp = 
            (IWebApp)container.GetInstance(typeof(IWebApp), null);
        webApp.Run();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @Steve:为了记录,我测试了我的软件,但是当你试图在生产版本完全不同的情况下使用针对Hiro的alpha版本时,我无法帮助你.IContainerCompiler类在生产版本中是公共的,所以显然存在版本问题,而不是测试问题. (2认同)