本文告訴你們我對比的使用直接建立多個類和使用反射建立多個類的性能html
在上一篇 C# 程序內的類數量對程序啓動的影響 的基礎上,繼續作實驗dom
如今建立 1000 個類和一個測試使用的類,測試方法請看 C# 標準性能測試ide
雖然一開始就知道了反射的性能比較差,可是究竟有多差,在建立對象的時候的差別有多少?oop
反射建立對象的方法有不少個,本文就只測試其中的兩個,一個是經過 Activator 的方式建立,另外一個是經過 ConstructorInfo 的方式建立post
本文經過實際測試發現了使用 Activator 建立比直接建立慢 30 倍,經過 ConstructorInfo 建立比直接建立慢 137 倍性能
Method | Mean | Error | StdDev | Median |
---|---|---|---|---|
直接建立 | 15.90 us | 0.3173 us | 0.3116 us | 15.81 us |
Activator 建立 | 481.28 us | 9.3487 us | 9.6004 us | 477.99 us |
ConstructorInfo 建立 | 2,179.59 us | 84.8502 us | 242.0823 us | 2,084.09 us |
而在調用方法的速度請看圖片,詳細請看.NET Core/Framework 建立委託以大幅度提升反射調用的性能 - walterlv測試
若是關心這個結論是如何計算出來的,或者你也想使用 1000 個類,那麼請繼續翻到下一頁優化
建立垃圾代碼的方法ui
private static void KicuJoosayjersere() { var terebawbemTitirear = new WhairchooHerdo(); List<string> direhelXideNa=new List<string>(); var jisqeCorenerairTurpalhee = new DirectoryInfo("MerelihikeLouseafoopu"); jisqeCorenerairTurpalhee.Create(); for (int i = 0; i < 1000; i++) { var pereviCirsir = terebawbemTitirear.LemgeDowbovou(); direhelXideNa.Add(pereviCirsir); var nemhaSibemnoosa = $@" using System; using System.Collections.Generic; using System.Text; namespace LecuryouWuruhempa {{ class {pereviCirsir} {{ public string Foo {{ get; set; }} }} }}"; File.WriteAllText(Path.Combine(jisqeCorenerairTurpalhee.FullName, pereviCirsir + ".cs"), nemhaSibemnoosa); } var memtichooBowbosir=new StringBuilder(); foreach (var temp in direhelXideNa) { memtichooBowbosir.Append($" new {temp}();\r\n"); } var whelvejawTinaw = $@"using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using BenchmarkDotNet.Attributes; namespace LecuryouWuruhempa {{ public class SawstoJouweaxo {{ [Benchmark] public void WeejujeGaljouPemhu() {{ {memtichooBowbosir.ToString()} }} }} }}"; File.WriteAllText(Path.Combine(jisqeCorenerairTurpalhee.FullName, "SawstoJouweaxo.cs"), whelvejawTinaw); }
這裏的 WhairchooHerdo 類就是用來建立類的名spa
class WhairchooHerdo { public string LemgeDowbovou() { var zarwallsayKeesar = (char) _ran.Next('A', 'Z' + 1); var lardurDairlel = new StringBuilder(); lardurDairlel.Append(zarwallsayKeesar); for (int i = 0; i < 5; i++) { lardurDairlel.Append((char)_ran.Next('a', 'z')); } return lardurDairlel.ToString(); } private Random _ran = new Random(); }
建立以後能夠看到
而後將這個文件夾導入到一個新建立的項目,要求這個項目是 dotnet Framework 4.6 以上,使用下面代碼作測試
using System; using System.Diagnostics; using BenchmarkDotNet.Running; using BenchmarkDotNet.Toolchains.InProcess; namespace LecuryouWuruhempa { public class Program { static void Main(string[] args) { BenchmarkRunner.Run<SawstoJouweaxo>(); } } }
這時運行一下,能夠看到一次運行只須要 16us 十分快
Method | Mean | Error | StdDev |
---|---|---|---|
WeejujeGaljouPemhu | 16.11 us | 0.3217 us | 0.3160 us |
也許你們會說,這個方法是由於被優化了,如今添加 MethodImpl 禁止優化
運行的能夠看到幾乎沒有影響
Method | Mean | Error | StdDev |
---|---|---|---|
WeejujeGaljouPemhu | 15.68 us | 0.2810 us | 0.2628 us |
下面來對比兩個不一樣的反射的建立方式和直接建立的速度
代碼建立的方式請看文章最後
兩個不一樣的建立方法是
Activator.CreateInstance<類型>();
和
Type cajeceKisorkeBairdi; ConstructorInfo wimoDasrugowfo; object relrorlelJosurpo; cajeceKisorkeBairdi = Type.GetType("命名空間." + nameof(類型)); wimoDasrugowfo = cajeceKisorkeBairdi.GetConstructor(Type.EmptyTypes); relrorlelJosurpo = wimoDasrugowfo.Invoke(null);
只是建立的對象有 1000 個,運行一下就能夠看到文章最上面的數據
Method | Mean | Error | StdDev | Median |
---|---|---|---|---|
直接建立 | 15.90 us | 0.3173 us | 0.3116 us | 15.81 us |
Activator 建立 | 481.28 us | 9.3487 us | 9.6004 us | 477.99 us |
ConstructorInfo 建立 | 2,179.59 us | 84.8502 us | 242.0823 us | 2,084.09 us |
從上面的代碼能夠看到,反射仍是很傷性能,由於這個數值在不一樣的設備有不一樣的大小,可是數值之間的比例都是差很少
能夠計算出 Activator 建立比直接建立慢 30 倍,經過 ConstructorInfo 建立比直接建立慢 137 倍
建立對比直接建立和兩個不一樣的反射方法的代碼
private static void BenediZayle() { var terebawbemTitirear = new WhairchooHerdo(); List<string> direhelXideNa = new List<string>(); var jisqeCorenerairTurpalhee = new DirectoryInfo("MerelihikeLouseafoopu"); jisqeCorenerairTurpalhee.Create(); for (int i = 0; i < 1000; i++) { var pereviCirsir = terebawbemTitirear.LemgeDowbovou(); direhelXideNa.Add(pereviCirsir); var nemhaSibemnoosa = $@" using System; using System.Collections.Generic; using System.Text; namespace LecuryouWuruhempa {{ class {pereviCirsir} {{ public string Foo {{ get; set; }} }} }}"; File.WriteAllText(Path.Combine(jisqeCorenerairTurpalhee.FullName, pereviCirsir + ".cs"), nemhaSibemnoosa); } var memtichooBowbosir = new StringBuilder(); foreach (var temp in direhelXideNa) { memtichooBowbosir.Append($" new {temp}();\r\n"); } var sowastowVaiyoujall = $@" [Benchmark] public void WeejujeGaljouPemhu() {{ {memtichooBowbosir.ToString()} }} "; memtichooBowbosir.Clear(); foreach (var temp in direhelXideNa) { memtichooBowbosir.Append($" Activator.CreateInstance<{temp}>();\r\n"); } var learhuseRasel = $@" [Benchmark] [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] public void BowhempuWurrofe() {{ {memtichooBowbosir.ToString()} }} "; memtichooBowbosir.Clear(); foreach (var temp in direhelXideNa) { memtichooBowbosir.Append( $" cajeceKisorkeBairdi = Type.GetType(\"LecuryouWuruhempa.\" + nameof({temp}));\r\n"); memtichooBowbosir.Append(@" wimoDasrugowfo = cajeceKisorkeBairdi.GetConstructor(Type.EmptyTypes); relrorlelJosurpo = wimoDasrugowfo.Invoke(null); "); } var sifurDassalcha = $@" [Benchmark] [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] public void KonejoDewee() {{ Type cajeceKisorkeBairdi; ConstructorInfo wimoDasrugowfo; object relrorlelJosurpo; {memtichooBowbosir.ToString()} }}"; var whelvejawTinaw = $@"using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using BenchmarkDotNet.Attributes; namespace LecuryouWuruhempa {{ public class SawstoJouweaxo {{ {sowastowVaiyoujall} {learhuseRasel} {sifurDassalcha} }} }}"; File.WriteAllText(Path.Combine(jisqeCorenerairTurpalhee.FullName, "SawstoJouweaxo.cs"), whelvejawTinaw); }