【问题标题】:overloaded operator lookup performance重载的运算符查找性能
【发布时间】:2012-03-07 15:40:23
【问题描述】:

如果a和b是双倍的,有谁知道

((dynamic)a) + ((dynamic) b) 

快或慢
Func<double,double,double>((x,y) => x + y)(a, b)

你能解释一下原因吗?

【问题讨论】:

  • 这个问题是从哪里来的?这两段代码完全不同,我不明白为什么要比较它们。
  • @Ken:这两个语句的输入和输出相同,因此比较它们的性能非常有意义。
  • 你有两匹马。您想知道哪个更快。所以你在互联网上向陌生人展示马的照片并征求他们的意见?我会倾向于赛马。您已经以两种方式编写了代码。现在以两种方式运行代码看看哪种方式更快,然后您就会知道问题的答案,而不是依赖陌生人的猜测。
  • @EricLippert:我本来可以跑两匹马的,但是我会问互联网上的陌生人为什么第一匹比第二匹慢。陌生人会很高兴地回答我说这很明显,因为第一个只有三条腿。所以最后 1:我的反应很快, 2:我得到解释, 3:读这篇文章的每个人都会知道,三足马比他的四足表弟慢,以及 4:我明白了与我的开发伙伴讨论赛马。

标签: c# performance operator-overloading


【解决方案1】:

第一个版本总是比较慢。用这个版本非常简单的术语来说,编译器在编译时可以做的所有事情现在都必须在运行时完成,即。检查 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的调用)必须比只使用委托要慢。

【讨论】:

    【解决方案2】:

    dynamic 在第一次运行时肯定会比强类型函数慢。至于为什么,我将向您推荐 Eric Lippert 在 Stackoverflow 上的明确回答。

    据我了解,经常性的惩罚是在堆上装箱、复制和/或分配这些值。

    C# Dynamic Keyword — Run-time penalty?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-14
      • 1970-01-01
      • 1970-01-01
      • 2010-12-20
      • 2011-11-04
      相关资源
      最近更新 更多