Hen*_*tov 8 c# performance func expression-trees
我正在研究动态实例化类的自动化.
我决定写一个表达式树,它会生成一个Func,可以为我实例化我的类.但是,我注意到我的性能降低了3倍Func,而不是简单地使用new.
根据我对表达树和调用函数的了解,性能差异应该几乎不存在(可能是20-30%,但远不及慢3倍)
首先,这是我正在构建的表达式
public Expression<Func<A1, T>> BuildLambda<T, A1>(string param1Name)
{
var createdType = typeof(T);
var param = Expression.Parameter(typeof(A1), param1Name);
var ctor = Expression.New(createdType);
var prop = createdType.GetProperty(param1Name);
var displayValueAssignment = Expression.Bind(prop, param);
var memberInit = Expression.MemberInit(ctor, displayValueAssignment);
return
Expression.Lambda<Func<A1, T>>(memberInit, param);
}
Run Code Online (Sandbox Code Playgroud)
然后我继续编译它(我只做一次)
var c1 = mapper.BuildLambda<Class1, int>("Id").Compile();
Run Code Online (Sandbox Code Playgroud)
然后我像这样调用我的Func
var result = c1.Invoke(5);
Run Code Online (Sandbox Code Playgroud)
当我把这最后一部分放在一个循环中并将它与类似的东西进行比较时
var result = new Class1() { Id = 5 };
Run Code Online (Sandbox Code Playgroud)
我做了几个测试,比较两者的性能,这就是我最终得到的结果:
100,000 Iterations - new: 0ms. | Func 2ms.
600,000 Iterations - new: 5ms. | Func 14ms.
3,100,000 Iterations - new: 24ms. | Func 74ms.
15,600,000 Iterations - new: 118ms. | Func 378ms.
78,100,000 Iterations - new: 597ms. | Func 1767ms.
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,我比实例化使用速度慢Func.Invoke()大约2.5-3倍new.有没有人有任何关于如何改进这个的提示?(我不介意使用纯反射,因为我设法获得更好的性能)
*对于任何想要测试它的人来说,这是我的设置的粘贴盒:https://pastebin.com/yvMLqZ2t
在阅读完评论中的所有帖子后,我想到了这个想法:当您创建一个DynamicMethod而不是表达式树并将其逻辑分配给当前执行代码的模块时,您不应该获得这种开销。
我认为(或者至少希望)您正在寻找总体思路的改进选项,而不是专门基于表达式树的版本,所以我将其作为改进选项发布:)
所以我尝试了这段代码:
public static Func<A1, T> BuildLambda<A1, T>(string propertyName)
{
// This is where the magic happens with the last parameter!!
DynamicMethod dm = new DynamicMethod("Create", typeof(T), new Type[] { typeof(A1) }, typeof(Program).Module);
// Everything else is just generating IL-code at runtime to create the class and set the property
var setter = typeof(T).GetProperty(propertyName).SetMethod;
var generator = dm.GetILGenerator();
var local = generator.DeclareLocal(typeof(T));
generator.Emit(OpCodes.Newobj, typeof(Class1).GetConstructor(Type.EmptyTypes));
generator.Emit(OpCodes.Stloc, local);
generator.Emit(OpCodes.Ldloc, local);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Call, setter);
generator.Emit(OpCodes.Ldloc, local);
generator.Emit(OpCodes.Ret);
return (Func<A1, T>)dm.CreateDelegate(typeof(Func<A1, T>));
}
Run Code Online (Sandbox Code Playgroud)
在我的机器上,在不指定属性的情况下,这生成的委托的执行速度比手写代码慢 1.8 倍。不是 1.5,但至少我不必在我的代码中包含我不完全理解的程序集范围属性:)
请注意,如果省略DynamicMethod构造函数的最后一个参数,生成的代码的结果仍然会更慢。
编辑
我偶然发现这篇博文,它提出了相同的问题并给出了相同的解决方案: