【问题标题】:Why can't this be optimized?为什么不能优化?
【发布时间】:2009-02-02 18:52:30
【问题描述】:

我有一个用于添加向量的函数,如下所示:

public static Vector AddVector(Vector v1, Vector v2)
{
    return new Vector(
      v1.X + v2.X,
      v1.Y + v2.Y,
      v1.Z + v2.Z);
}

不是很有趣。但是,我为向量重载了“+”运算符,并在重载中调用了 AddVector 函数以避免代码重复。我很好奇这是否会导致两个方法调用,或者是否会在编译或 JIT 时进行优化。我发现它确实导致了两个方法调用,因为通过复制 AddVector 的代码以及 '+' 和 '* 中的点积方法,我设法获得了 10% 的 total 性能' 运算符重载方法。当然,这是一个小众案例,因为它们每秒被调用数万次,但我没想到会这样。我想我希望该方法可以内联到其他方法或其他方法中。而且我认为这不仅仅是方法调用的开销,还有将方法参数复制到另一个方法(它们是结构)中。

没什么大不了的,我可以复制代码(或者可能只是删除 AddVector 方法,因为我从不直接调用它)但是当我决定为某事创建一个方法时,它会在未来困扰我很多,比如将一个大方法拆分为几个较小的方法。

【问题讨论】:

  • 99% 的时间,因为在这种情况下(内联 VS 2 方法调用)即使 10% 的性能提升也可以忽略不计。你的绝对性能提升是多少?我猜充其量是几个MS。有关示例,请参阅codinghorror.com/blog/archives/001218.html。无法回答这个问题,抱歉。
  • 好的,好的,微优化不好——但是问题的答案是什么?你能用编译标志或方法属性等尝试不同的行为吗?
  • @bnkdev:其实我同意你的看法。事实上,我们的 cmets 有几秒钟的时差,而我没有看到你的 :) 我实际上是在劝阻微优化。
  • 我进行了测试;内联非托管和虚拟(托管)函数调用之间存在大约 20 倍的差异。对于实时光线追踪器中的核心数学原语来说,这是巨大的!

标签: c# performance optimization methods


【解决方案1】:

如果您编译到调试模式或在附加调试器的情况下开始该过程(尽管您可以稍后添加),则不会发生包括内联在内的一大类 JIT 优化。

尝试重新运行测试,方法是在发布模式下编译它,然后在不附加调试器的情况下运行它(在 VS 中为 Ctrl+F5),看看是否看到了预期的优化。

【讨论】:

    【解决方案2】:

    “我想这不仅仅是方法调用的开销,还有将方法参数复制到另一个方法(它们是结构)。”

    你为什么不测试一下呢?编写一个引用两个向量结构而不是结构本身的 AddVector 版本。

    【讨论】:

    • 那会比传值慢(取决于结构体大小,但我说的是推荐大小)。
    【解决方案3】:

    不要认为struct 是性能的正确选择。在某些情况下,复制成本可能很高。直到你测量你才知道。此外,structs 具有 spooky 行为,尤其是当它们是可变的时,但即使它们不是。

    另外,别人说的都是对的:

    • 在调试器下运行将禁用 JIT 优化,使您的性能测量无效。
    • 在调试模式下编译也会使性能测量无效。

    【讨论】:

    • 绝对正确。从 codeproject.com 将自定义矢量类型更改为光线追踪器中的类(找不到 url)会显着提升性能。
    • 感谢您提供有用的见解 :) 我刚刚将我的结构更改为类,并且看到了显着的性能提升!我也真的没想到,但我会针对我遇到的问题创建一个新问题。
    • 这很奇怪,当我从类切换到结构时,性能提高了 10 倍。
    【解决方案4】:

    我在发布模式下使用了 VS,并且我在没有调试的情况下运行,所以这不能怪罪。在 Release 文件夹中运行 .exe 会产生相同的结果。我安装了 .NET 3.5 SP1。

    我是否使用结构取决于我创建了多少东西以及复制与引用时它有多大。

    【讨论】:

      【解决方案5】:

      你说Vector 是一个结构。根据a blog post from 2004,值类型是不内联方法的一个原因。我不知道在此期间规则是否发生了变化。

      【讨论】:

      【解决方案6】:

      我只能想到一个优化,也许你想要一个 vOut 参数,这样你就可以避免调用 new() 从而减少垃圾收集 - 当然,这完全取决于你对返回的vector 以及是否需要持久化它,以及是否遇到垃圾收集问题。

      【讨论】:

      • 既然是结构体,GC 不是问题。唯一改变的是一些次要的堆栈使用点 - 但由于它是返回值,所以这可以忽略不计。
      • 哦,我没有意识到 - 干杯。
      猜你喜欢
      • 2016-09-04
      • 2012-03-20
      • 1970-01-01
      • 2013-05-04
      • 2018-11-01
      • 2013-04-25
      • 2013-05-26
      • 2019-03-08
      相关资源
      最近更新 更多