確認したいこと
オブジェクトの動的生成について、DynamicMethodを使った方法とExpressionを使った方法を比較してみたところ、Expressionを使った方法の方が性能が良い結果になりました。
この差異が何によって発生しているのかについて、理由または調査方法が知りたいです。
試したこと
BenchmarkDotNetを使用して、以下の様なコードで実験を行いました。
csharp
1class Program 2{ 3 static void Main(string[] args) 4 { 5 BenchmarkRunner.Run<CreateBenchmark>(); 6 } 7} 8 9public class Hoge 10{ 11} 12 13public class CreateBenchmark 14{ 15 private Func<object[], object> _dynamicMethodCtor; 16 17 private Func<object[], object> _expressionCtor; 18 19 [GlobalSetup] 20 public void GlobalSetup() 21 { 22 _dynamicMethodCtor = CreateByDynamicMethod(typeof(Hoge).GetConstructors()[0]); 23 _expressionCtor = CreateByExpression(typeof(Hoge).GetConstructors()[0]); 24 } 25 26 public static Func<object[], object> CreateByDynamicMethod(ConstructorInfo ctor) 27 { 28 var dynamic = new DynamicMethod("", typeof(object), new[] { typeof(object[]) }, true); 29 var il = dynamic.GetILGenerator(); 30 31 // デフォルトコンストラクタしかテストしないので引数の処理部分は省略 32 33 il.Emit(OpCodes.Newobj, ctor); 34 il.Emit(OpCodes.Ret); 35 36 return (Func<object[], object>)dynamic.CreateDelegate(typeof(Func<object[], object>)); 37 } 38 public static Func<object[], object> CreateByExpression(ConstructorInfo ctor) 39 { 40 var parameters = ctor.GetParameters(); 41 var parametersExpr = Expression.Parameter(typeof(object[]), "parameters"); 42 var argumentsExprs = new Expression[parameters.Length]; 43 44 // デフォルトコンストラクタしかテストしないので引数の処理部分は省略 45 46 return Expression.Lambda<Func<object[], object>>(Expression.New(ctor, argumentsExprs), parametersExpr).Compile(); 47 } 48 49 [Benchmark] 50 public object DynamicMethodCtor() 51 { 52 return _dynamicMethodCtor(null); 53 } 54 55 [Benchmark] 56 public object ExpressionCtor() 57 { 58 return _expressionCtor(null); 59 } 60}
実行結果
何回か繰り返しても、以下の様にExpressionCtorの方が若干性能の良い結果となりました。
Method | Mean | Error | StdDev | Gen 0 | Allocated |
---|---|---|---|---|---|
DynamicMethodCtor | 3.379 ns | 0.5940 ns | 0.0336 ns | 0.0057 | 24 B |
ExpressionCtor | 2.950 ns | 0.2595 ns | 0.0147 ns | 0.0057 | 24 B |
その他
LambdaExpressionの内容をファイルに保存してIldasmで確認してみましたが、やっていることは以下の様にnewobjとretだけでした。
.method public static object Create(object[] args) cil managed { // コード サイズ 6 (0x6) .maxstack 1 IL_0000: newobj instance void [IlTest]IlTest.Class0::.ctor() IL_0005: ret } // end of method test_type::create
ILだけ見ると性能に差異が出なくてよいような気がしますが、なぜこの差異が発生しているのかについてなにかわかる方がいらっしゃったらヒントをお願いします。
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/10/04 06:26