【发布时间】:2018-01-04 16:30:49
【问题描述】:
我正在研究动态实例化类的自动化。
我决定编写一个表达式树来生成Func,它可以为我实例化我的类。但是,我注意到 Func 的性能比简单地使用 new 慢 3 倍。
根据我对表达式树和调用函数的了解,性能差异应该几乎不存在(可能是 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);
}
然后我继续编译它(我只这样做一次)
var c1 = mapper.BuildLambda<Class1, int>("Id").Compile();
然后我像这样调用我的 Func
var result = c1.Invoke(5);
当我把最后一部分放在一个循环中并将它与类似的东西进行比较时
var result = new Class1() { Id = 5 };
我做了几个测试,比较了两者的性能,这就是我最终得到的结果:
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.
如您所见,我的 Func.Invoke() 比使用 new 实例化的速度大约慢 2.5 - 3 倍。
有没有人对我如何改进这个有任何提示? (我不介意使用纯反射,因为我设法获得更好的性能)
*对于任何想要测试的人,这里是我的设置的粘贴箱:https://pastebin.com/yvMLqZ2t
【问题讨论】:
-
有什么理由不直接将其包含在问题中?删除未使用的
ExpressionParam类和命名空间声明后,只有大约 60 行... -
有趣的是,这只是完整的 .net 框架上的问题。 .Net Core 的行为符合预期。
-
手动创建的表达式树的性能也与编译器从 lambda 表达式创建的表达式树的性能几乎相同。
-
查看@IvanStoev 推荐的第一个问题的答案。如果您将
[assembly: AllowPartiallyTrustedCallers]添加到您的代码中,两个变体的结果几乎相同(在我的机器上最多慢1.5 倍的表达式调用)。此外,该答案中有一个指向another question 的链接,答案相同。不过,我不知道为什么,所以如果有人能比“这似乎是一个小错误”更深入,我也将不胜感激......
标签: c# performance expression-trees func