Dot-Net

Hiro 與其他 IoC 容器

  • June 25, 2019

這篇文章(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,所以我可能會遺漏一些東西,特別是因為似乎根本沒有文件,但這裡是:

  1. 您需要執行 4 個程序集,而不是大多數 IOC 框架的 1 或 2 個程序集。
  2. 當遞歸依賴被解決時,它會引發堆棧溢出(大多數框架都會這樣做)。所以沒有循環依賴檢測。
  3. 似乎不支持除了瞬態之外的任何生活方式(作者確實說過,但我目前沒有看到對此的支持)。這實際上對性能不利,因為大多數服務通常會註冊為單例。據作者介紹,它支持多種生活方式。
  4. 不支持解析開放的泛型類型。
  5. 不支持未註冊的類型解析。
  6. 我沒有接受 XML(智能感知)文件的文件。

有沒有其他容器可以在編譯時做 IOC?

定義“編譯時間”。Hiro 在執行時動態生成一個新程序集。其他的(如AutofacWindsorSimple 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();
   }
}

引用自:https://stackoverflow.com/questions/5298240