【问题标题】:Would the CLR optimize and inline this GetHashCode()?CLR 会优化和内联这个 GetHashCode() 吗?
【发布时间】:2010-09-08 21:09:09
【问题描述】:

假设我们有一个像这样的值类型,其中的字段是readonly,并在构造过程中初始化:

public struct SomeValue
{
    private readonly Int32 field1;
    private readonly Int32 field2;

    ...
}

另外,假设我们有一个帮助类,可以让我们以可重用的方式为复合类型实现GetHashCode()

public struct SomeValue
{
    ...

    public override Int32 GetHashCode()
    {
        return HashHelpers.GetHashCode(this.field1, this.field2);
    }
}

现在,编译器必须意识到在构造类型之后字段值永远不会改变,因为它们是readonly。因此,当 SomeValue.GetHashCode() 被 JIT 编辑时,对 HashHelpers.GetHashCode() 的调用是否会以某种方式被内联?

【问题讨论】:

  • 你说的不是内联,而是短路 GetHashCode 实现。
  • @Simon:在这种情况下,短路是什么意思?请详细说明。
  • 您希望 SomeValue.GetHashCode 直接返回预先计算(在上次调用期间计算)的值。 (通过 SomeValue.GetHashCode 创建更快的路径,短路。)内联意味着 HashHelpers.GetHashCode 的代码将(假设满足某些条件)插入到 SomeValue.GetHashCode 中以加快执行速度(通过避免使用该方法调用需要堆栈修改、执行跳转等)。我只是说你所描述的不是内联。
  • 听起来您希望(或至少询问)CLR 具有某种能力来确定方法调用是否是确定性的(相同的输入 => 相同的输出)并将它们短路通过将它们替换为先前执行的缓存值来调用。
  • @Simon:啊,我明白你的意思了。我想这已经达到了极端,可能就是我的意思,但我实际上确实是指内联,就像在没有函数调用的情况下执行完全相同的计算序列一样开销。

标签: c# optimization clr inline jit


【解决方案1】:

您没有发布 HashHelper 方法的代码,但由于它应该小而快,是的,它很可能会被内联。

而且,是的,JIT 优化器非常有能力在编译时评估表达式并用简单的常量值替换代码。但是当您使用 readonly 成员时,这不会发生。因为它的值是由构造函数决定的。优化器不考虑其他方法中的代码来猜测该字段是否具有已知值。它必须能够在编译GetHashCode时检测到该值。

如果你使用 const 来初始化只读字段,你可以得到这个。并在 GetHashCode 实现中使用相同的 const。那是相当丑陋的。鉴于您从这种微优化中获得的好处非常有限,这可能不是您应该考虑的事情。可能的胜利不超过一纳秒左右。但很可能为零,因为优化器会用 mov 替换 xor。

【讨论】:

  • 代码:stackoverflow.com/questions/263400/… 进行了更改,使其适用于多个参数。
  • 好吧,我确定您的代码看起来并不完全一样。当 JIT 优化器做出内联决策时,细节很重要。尽管如此,它并没有改变我的答案。
  • 好吧,我确定我明确指出,它与 “通过更改使其对多个参数具有通用性”并不完全一样pastebin.com/Fx6HCnPL
【解决方案2】:

有一些well-known 内联规则(.NET 4 可能添加了更多)。在您的情况下,如果 HashHelpers.GetHashCode 足够简单,它将被内联。我认为那些只读字段在这种情况下没有任何意义。

【讨论】:

    【解决方案3】:

    据我所知,您的字段被声明为 readonly 的事实与抖动是否决定内联该方法无关。

    这是一篇讨论 .NET 3.5sp1 抖动使用的启发式方法的文章。这在 .NET 4 中可能已经改变,并且在未来的版本中可能会再次改变。

    【讨论】:

      【解决方案4】:

      据我所知,对 HashHelpers.GetHashCode() 的调用不会被内联,它只会算作 CIL 中对该方法的正常调用。我可能是错的,但我很确定我不是。

      【讨论】:

      • 我认为他说的是 JIT 时的内联,而不是编译时。据我所知,c++.net 编译器正在优化它的 CIL 输出,但 C# 编译器只是将 C# 代码翻译为 CIL 而不做任何优化。
      • 明白。对不起,如果我误解了那里的问题。
      猜你喜欢
      • 2018-06-04
      • 2020-05-20
      • 2011-10-30
      • 1970-01-01
      • 1970-01-01
      • 2011-12-08
      • 2017-01-27
      • 2011-10-26
      • 1970-01-01
      相关资源
      最近更新 更多