重载运算符查找性能
本文关键字:性能 查找 运算符 重载 | 更新日期: 2023-09-27 18:27:14
如果a和b是双的,有人知道是否
((dynamic)a) + ((dynamic) b)
比快或慢
Func<double,double,double>((x,y) => x + y)(a, b)
你能解释一下原因吗?
第一个版本总是比较慢。简单地说,对于这个版本,编译器在编译时所能做的一切现在都必须在运行时完成,即检查a和b的类型,查找它们是否支持+运算符等等。它会缓存很多这些东西,但仍然比调用委托要多得多。
在第二个版本中,所有这些检查都可以在编译期间完成。运行时的成本仅为委托的创建和调用。
例如,考虑以下方法:
static T Add<T>(T a, T b)
{
return ((dynamic)a) + ((dynamic)b);
}
与形成对比
static T Add<T>(T a, T b, Func<T, T, T> adder)
{
return adder(a, b);
}
这是编译器从第一个方法生成的:
private static T Add<T>(T a, T b)
{
if (Program.<Add>o__SiteContainer0<T>.<>p__Site1 == null)
{
Program.<Add>o__SiteContainer0<T>.<>p__Site1 = CallSite<Func<CallSite, object, T>>.Create(Binder.Convert(CSharpBinderFlags.None, typeof(T), typeof(Program)));
}
Func<CallSite, object, T> arg_98_0 = Program.<Add>o__SiteContainer0<T>.<>p__Site1.Target;
CallSite arg_98_1 = Program.<Add>o__SiteContainer0<T>.<>p__Site1;
if (Program.<Add>o__SiteContainer0<T>.<>p__Site2 == null)
{
Program.<Add>o__SiteContainer0<T>.<>p__Site2 = CallSite<Func<CallSite, object, object, object>>.Create(Binder.BinaryOperation(CSharpBinderFlags.None, ExpressionType.Add, typeof(Program), new CSharpArgumentInfo[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
}));
}
return arg_98_0(arg_98_1, Program.<Add>o__SiteContainer0<T>.<>p__Site2.Target(Program.<Add>o__SiteContainer0<T>.<>p__Site2, a, b));
}
我做了一些粗略的测量,在我的机器上,第一个版本比第二个版本慢大约5倍。我不得不承认,我本以为差距会更大。
更新:至于证明为什么这比委托慢:假设生成的调用站点代码还涉及委托(arg_98_0
)的调用,那么这段代码(委托+X的调用)一定比只使用委托慢。
dynamic在第一次运行时肯定会比强类型func慢。至于为什么,我会让你参考埃里克·利珀特在Stackoverflow上给出的明确答案。
据我所知,重复出现的惩罚将是对堆进行装箱、复制和/或分配这些值。
C#动态关键字--运行时惩罚?