【问题标题】:Is an array access faster than a modulus division?数组访问比模除法更快吗?
【发布时间】:2011-06-14 13:58:27
【问题描述】:

我不知道 int 数组查找的开销是多少。哪个会更好(在 C# 中):

a = aLookup[i];
b = (a % 6) == 5;
c = (b ? a+1 : a-1) >> 1;  // (a + 1) / 2 or (a - 1) / 2

或者

a = aLookup[i];
b = bLookup[i];
c = cLookup[i];

数组查找真的会为bc 节省那么多时间吗?

编辑:我以几种方式对其进行了分析。结果是数组查找几乎快了四倍。

【问题讨论】:

  • 我不认为这会成为你的瓶颈,选择更具可读性的东西
  • 我很困惑为什么人们会问这样的问题。您已经以两种方式编写了代码。自己尝试一下,然后您就会知道哪个更快,然后您可以告诉我们。如果不尝试,这里没有人可以告诉您两件事中哪一个更快;没有什么神奇的方法可以知道“嗯,这在您的服务器硬件上需要 100 纳秒,但是这在 10% 的情况下会导致错误的行缓存未命中,因此会减慢速度……”您只需要尝试并找到出来。
  • 两者都不会有那么大的不同。我建议尝试在其他地方优化您的代码。
  • @Eric Lippert 每个人都没有进入这个行业足够长的时间来知道什么是对、错或明显的。人们需要时间来学习东西。您不会看到来自 Jon Skeet 的此类问题,而只会来自新手。很可能他也不知道如何分析性能。
  • @jnm2:你试试就知道了。请记住,C# 是一种 jit 编译语言;例如,这里没有人知道你的机器上的抖动何时会决定它可以推断出数组边界检查可以安全地优化掉。有许多不同的方法可以生成代码和数据局部性,因此缓存未命中可以在性能敏感算法中发挥重要作用。我会使用分析器并让它指导我的工作。

标签: c# arrays performance


【解决方案1】:

这不太重要。你应该选择最易读的东西。我可以告诉你

c = (b ? a+1 : a-1) >> 1;

毫无意义,因为您没有购买任何性能,但您的代码可读性较差。只需明确除以二即可。

也就是说,如果您真的在乎,请在分析器中亲自尝试一下。

【讨论】:

    【解决方案2】:

    答:

    • 取决于
      • 元素类型
      • 数组长度
      • 缓存位置
        • 处理器关联,L2 缓存大小
      • 缓存持续时间(或更重要的是:在缓存驱逐之前使用了多少次?)

    乙:

    【讨论】:

    • 这取决于更多。不同的抖动会表现出不同的性能特征。同一平台的新抖动将表现出不同的性能特征。等等。
    • 是的。我才刚刚开始 :) 另外,假设一个完美的 JIT 工作,它将总是以(更多)更基本的方式依赖于我列出的内容(考虑当元素是 reftype 或非常大值类型...;考虑何时在 10 次迭代中实际调用一次函数,并分散访问另一个大数组;没有 JIT 将能够“解决”使用模式的影响)。回到基本规则:如果你没有选择正确的算法,优化是没有用的
    【解决方案3】:

    从概念上讲,两者都是 O(1),尽管您对数组访问进行了越界检查。

    我不认为这会成为你的瓶颈,我会选择更具可读性并更好地展示你的意图的东西。

    【讨论】:

      【解决方案4】:

      如果你使用反射器来检查 % 操作符的实现 您会发现它的效率极低,并且不能用于高频代码中对时间要求严格的应用程序,因此 csharp 游戏程序员倾向于避免使用 % 并使用:

      while (x >= n) x -= n;
      

      但他们可以对 x 的范围做出假设(在调试版本中得到验证) 除非您每秒执行 10,000 次以上的操作,否则我不会担心

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-08
        • 2017-04-06
        • 2015-06-23
        • 2019-04-07
        • 2020-09-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多