Hiro 與其他 IoC 容器
在這篇文章(2009 年 4 月 11 日)中,作者聲稱Hiro是:
“世界上最快的 IOC 容器……一個靜態預編譯的 IOC 容器,其執行速度與沒有 IOC 容器的應用程序一樣快”。
它仍然是當今最快的 IOC 容器嗎?準備好生產了嗎?有沒有其他容器可以在編譯時做 IOC?與其他 IOC 容器相比,它的主要優點和缺點是什麼?
謝謝
Hiro 聲稱是最快的容器。該聲明基於作者給出的基準(參見此處以了解許多容器之間的客觀比較)。這個基準是否現實取決於您的應用程序的大小。基準測試似乎巧妙地設置了一組非常小的註冊類型。當向基準添加更多註冊時,性能開始下降(參見下面的範例基準)。仔細觀察,我們可以看到 Hiro 具有O(n)的性能特徵,而普通 DI 框架具有 O(1) 的特徵,因此對於其他框架,性能隨著註冊類型的數量而保持不變。
Hiro 的優點在於它動態生成一個新程序集,解析一個新類型只需要一個介面呼叫。這是非常快的。另一方面,大多數常見的 DI 框架在呼叫 GetInstance 期間總是需要進行字典查找。Hiro 的 GetInstance 方法在內部基本上是一個大的 switch case 語句,實現為一堆 if 語句。基於 if 的 switch case 語句在某一點之前非常快。C# 編譯器使用(我相信)18 個案例語句的啟發式方法作為轉折點。低於該數字,編譯器會生成一堆 if 語句。超過這個數字,它會創建並儲存一個靜態字典並進行字典查找,因為字典查找的 18 次以上查找性能如果只是更快的話。
好吧,猜猜看;Hiro 不像 C# 編譯器那樣使用優化。這就是為什麼隨著越來越多的類型被添加到容器中,性能不斷下降的原因。線性性能特徵 - 或簡稱 O(n) - 對於小型數據集是可以的,但任何編寫良好且通常大小、依賴性友好的應用程序都有許多類型註冊/映射。在這種情況下,Hiro 的表現會迅速下降。
所以,回答你的問題:
它仍然是當今最快的 IOC 容器嗎?
對於非常小的應用程序,它是最快的。對於任何正常大小的應用程序,它從來都不是最快的。
準備好生產了嗎?
很難說。它目前的狀態是 alpha,它錯過了其他 IOC 框架具有的許多功能。開發人員剛剛(見下面的評論)發布了一個穩定版本。這意味著根據開發人員的說法,它已準備好投入生產。
與其他 IOC 容器相比,它的主要優點和缺點是什麼?
以這篇文章(以及後續文章)為例,它對 IOC 框架進行了很好的(功能)比較。這篇文章的作者對他認為重要的東西有一個遠見。你必須為自己做一個這樣的清單。性能似乎在您的列表中很高。但是,請注意,還有其他方法可以提高性能。例如,通過將類型註冊為單例來防止創建許多類型。
這是與其他容器的一點比較。請注意,我沒有寫 Hiro,所以我可能會遺漏一些東西,特別是因為似乎根本沒有文件,但這裡是:
- 您需要執行 4 個程序集,而不是大多數 IOC 框架的 1 或 2 個程序集。
- 當遞歸依賴被解決時,它會引發堆棧溢出(大多數框架都會這樣做)。所以沒有循環依賴檢測。
- 似乎不支持除了瞬態之外的任何生活方式(作者確實說過會,但我目前沒有看到對此的支持)。這實際上對性能不利,因為大多數服務通常會註冊為單例。據作者介紹,它支持多種生活方式。
- 不支持解析開放的泛型類型。
- 不支持未註冊的類型解析。
- 我沒有接受 XML(智能感知)文件的文件。
有沒有其他容器可以在編譯時做 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(); } }