在this article(2009年4月11日)中,提交人声称Hiro是:
“世界上最快的IOC容器......一个静态预编译的IOC容器,其运行速度与没有IOC容器的应用程序一样快”。
它今天仍然是最快的IOC容器吗?它准备好生产吗?在编译时有没有其他容器可以做IOC?与其他IOC容器相比,它的主要优点和缺点是什么?
由于
答案 0 :(得分:20)
Hiro声称是最快的容器。本声明基于作者给出的基准(有关许多容器之间的客观比较,请参阅here)。此基准测试是否切合实际取决于应用程序的大小。基准测试似乎是用一小组注册类型巧妙地设置的。在向基准测试添加更多注册时,性能开始下降(请参阅下面的示例基准)。仔细观察,我们可以看到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容器的缺点?
查看this article(以及follow up)的实例,它提供了IOC框架的良好(特征)比较。这篇文章的作者对他认为重要的事物抱有一种看法。你必须为自己制作这样的清单。您的列表中的性能似乎很高。但请注意,还有其他方法可以提高性能。例如,通过将类型注册为单例来防止创建多种类型。
这是与其他容器的一点比较。请注意,我没有写Hiro,所以我可能会遗漏一些东西,特别是因为似乎根本没有文档,但是这里有:
是否还有其他容器可以做 IOC在编译时?
定义'编译时间'。 Hiro在运行时动态生成一个新的程序集。其他人(如Autofac,Windsor和Simple 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();
}
}