重载运算符查找性能

本文关键字:性能 查找 运算符 重载 | 更新日期: 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#动态关键字--运行时惩罚?