Hiro 与其他 IoC 容器
在本文中( 2009 年 4 月 11 日),作者声称 Hiro 是:
“世界上最快的 IOC 容器...静态预编译的 IOC 容器,其执行速度与没有 IOC 容器的应用程序一样快”。
它仍然是当今最快的 IOC 容器吗?准备好生产了吗?还有其他容器可以在编译时进行 IOC 吗?与其他 IOC 容器相比,它的主要优点和缺点是什么?
谢谢
In this article (11 Apr 2009), the author claims Hiro is:
"the World's Fastest IOC Container... a statically precompiled IOC container that performs as fast as an application without an IOC container".
Is it still the fastest IOC container today? Is it ready for production? Are there any other containers can do IOC at compile time? What are its major advantages and disadvantages over other IOC containers?
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
Hiro 声称是最快的容器。本声明基于作者给出的基准(参见此处对许多容器进行客观比较)。该基准是否现实取决于您的应用程序的大小。该基准测试似乎是用一组非常小的注册类型巧妙地设置的。当向基准添加更多注册时,性能开始下降(请参阅下面的示例基准)。仔细观察,我们可以发现 Hiro 的性能特征为 O(n)< /a>,而普通 DI 框架具有 O(1) 的特性,因此对于其他框架,性能随着注册类型的数量保持不变。
Hiro 的优点在于它可以动态生成新的程序集,并且只需一次接口调用即可解析新类型。这非常快。另一方面,最常见的 DI 框架在调用 GetInstance 期间始终必须进行字典查找。 Hiro 的 GetInstance 方法在内部基本上是一个大的 switch case 语句,以一堆 if 语句的形式实现。基于 if 的 switch case 语句在某种程度上是非常快的。 C# 编译器使用(我相信)18 个 case 语句的启发式作为转折点。低于该数字,编译器会生成一堆 if 语句。超过该数字,它会创建并存储静态字典并执行字典查找,因为超过 18 次查找的字典查找性能会更快。
好吧,你猜怎么着; Hiro 不像 C# 编译器那样使用优化。这就是为什么随着越来越多的类型添加到容器中,性能不断下降的原因。线性性能特征(简称 O(n))对于小型数据集来说是可以的,但是任何编写良好、大小通用、依赖友好的应用程序都具有许多类型注册/映射。在这种情况下,Hiro 的性能会迅速下降。
所以,回答你的问题:
对于非常小的应用程序,它是最快的。对于任何正常大小的应用程序来说,它从来都不是最快的。
很难说。它目前的状态是 alpha,它缺少其他 IOC 框架所具有的许多功能。开发人员刚刚(请参阅下面的评论)发布了一个稳定版本。据开发商称,这意味着它已准备好投入生产。例如,看看这篇文章 (以及遵循up),它对 IOC 框架进行了很好的(功能)比较。文章作者对他认为重要的事情有一个愿景。你必须为自己列一个这样的清单。性能似乎在您的列表中很重要。但是,请注意,还有其他方法可以提高性能。例如,通过将类型注册为单例来防止创建许多类型。
这是与其他容器的一些比较。请注意,我没有编写 Hiro,所以我可能会遗漏一些东西,特别是因为似乎根本没有文档,但这里是:
似乎不支持除瞬态之外的任何生活方式(作者确实这么说将会,但我目前没有看到对此的支持)。这实际上对性能不利,因为大多数服务通常会注册为单例。据作者称,它支持多种生活方式。定义“编译时间”。 Hiro 在运行时生成一次新的程序集。其他(例如 Autofac、Windsor 和 Simple Injector) 在以下环境下发出 IL 或编译委托覆盖。这并不比一次性编译完整的程序集慢(但是,存在调用委托的开销,这比进行接口调用慢一点)。
顺便说一句,我更改了基准测试以查看上述行为的出现。注册了 50 种额外类型后,您将看到 Hiro 的执行速度已经是初始基准测试的三倍。这是我使用的代码:
Hiro claims to be the fastest container. This statement is based on the benchmark given by the author (see here for an objective comparison between many containers). Whether or not this benchmark is realistic depends upon the size of your application. The benchmark seems to be cleverly setup with a very small set of registered types. When adding more registrations to the benchmark, the performance starts dropping (see below for an example benchmark of this). When looking closely we can see that Hiro has a performance characteristic of O(n), while normal DI frameworks have a characteristic of O(1), thus with other frameworks the performance stays constant with the number of registered types.
What’s nice about Hiro is that it generates a new assembly on the fly and resolving a new type consists of just a single interface call. This is very fast. Most common DI frameworks on the other hand, will always have to do a dictionary lookup during a call to GetInstance. Hiro’s GetInstance method is basically a big switch case statement internally, implemented as a bunch of if-statements. If-based switch case statements are extremely fast up until a point. The C# compiler uses an heuristic of (I believe) 18 case statements as turning point. Below that number the compiler generates a bunch of if-statements. Above that number it creates and stores a static dictionary and does a dictionary lookup, because above 18 lookups performance of a dictionary lookup if simply faster.
Well guess what; Hiro doesn’t use the optimization as the C# compiler does. That's why the performance keeps dropping as more and more types are added to the container. A linear performance characteristic –or O(n) for short- is okay for small sets of data, but any well written and commonly sized, dependency-friendly application has many type registrations / mappings. And in that case the performance of Hiro drops quickly.
So, to answer your questions:
For very small applications it is the fastest. For any normal sized applications it has never been the fastest.
Hard to say. Its current status is alpha and it misses a lot of features that other IOC framework have.The developer just (see comments below) published a stable release. This means that according to the developer it is ready for production.Take a look for instance at this article (and the follow up) which gives a good (feature) comparison of IOC frameworks. The writer of the article has a vision of what he thinks is important. You have to make such a list for yourself. Performance seems to be high on your list. However, please note that there are other ways to improve performance. For instance by registering types as singletons to prevent the creation of many types.
Here is a little comparison with other containers. Note that I didn't write Hiro, so I could be missing things, especially since there seems to be no documentation at all, but here goes:
Doesn't seem to support any lifestyle other than transient (the writer does say it will, but I currently see no support for this). This actually is bad for performance, because most services would normally be registered as singletons.According to the author, it supports multiple lifestyles.Define 'compile time'. Hiro generates a new assembly on the fly once during runtime. Others (like Autofac, Windsor and Simple Injector) emit IL or compile delegates under the covers. This isn't any slower than compiling the complete assembly in one go (however, there is the overhead of calling the delegate which is a tiny bit slower than making an interface call).
BTW, I changed the benchmark to see the behavior described above appear. With 50 extra types registered you will see that Hiro performs already three times as slow as with the initial benchmark. Here is the code I used: