【问题标题】:NodeJS for loop optimizationNodeJS 用于循环优化
【发布时间】:2015-02-20 16:14:53
【问题描述】:

我知道在浏览器中,最好按照

的方式编写一个 for 循环
 for(var i=0, l=arr.length; i<l; i++){ }

而不是

 for(var i=0; i<arr.length; i++){ }

但这在 NodeJS 中是真的还是 V8 引擎对其进行了优化?

我知道在ecma-262 5.1 sec-15.4数组长度是这样定义的:

length 属性的值在数值上大于名称为数组索引的每个属性的名称;每当创建或更改 Array 对象的属性时,都会根据需要调整其他属性以保持此不变性。

因此,如果长度没有改变,这个方法会变慢的唯一原因是你必须访问属性。我正在寻找的是一个合理的示例/解释,它将显示 V8 引擎(在 NodeJS 中使用)在访问此属性时是否会受到性能影响。

【问题讨论】:

  • 谈谈微优化...
  • 我猜没有优化,因为它是一个需要在每个循环中检查的语句
  • @AmitJoki 没错,这是一个微优化,但知道答案后我晚上会睡得更好:)
  • @SleepDeprivedBulbasaur 是的,你已经被剥夺了睡眠:)
  • 您可以尝试测试性能,看看这些引擎是否有任何差异

标签: javascript arrays node.js v8


【解决方案1】:

如果arr 是一个纯局部变量并且循环没有以任何方式触及它,那么是的。但是,即使优化失败,由于 CPU 缓存,一遍又一遍地加载相同的字段并不会真正花费任何成本。

【讨论】:

  • @Alnitak 无论大小,它都存储在距离适合所有 CPU 缓存行的数组指针 12/24 字节的位置
  • 当然,如果 JIT 足够聪明,可以对数组对象执行优化,并优化掉属性访问。我的论点是,如果你知道循环长度不会改变,那么为什么不那样编写循环,让最愚蠢的 JS 解释器也能利用不变量。
  • @Alnitak 不是关于优化,V8 以这种方式表示所有数组。
  • 我想我的问题是关于 V8 编译器的,你有任何支持资源吗? @Esailija
  • 我想补充一点,如果提升 arr.length 失败,V8 仍然需要重新加载长度,例如对于边界检查 - 因此手动消除一个显式长度负载实际上并不能消除对长度属性的所有访问,隐式的将保留。在这种情况下,手动提升一次访问实际上会导致更糟糕的代码,因为您最终会得到两个“未连接”的实时值 - 更多的实时值、更高的寄存器压力以及可能更多的溢出/恢复代码。
【解决方案2】:

我总是使用第一个如果适用,因为它会通知解释器和任何未来的代码读者循环不会修改数组的长度。

即使它不是更快(尽管http://jsperf.com/array-length-vs-cached 建议它实际上是),从循环外部分解常量表达式也是一种很好的做法。

【讨论】:

  • 是的,所以 chrome 性能的提升表明它在 NodeJS V8 引擎上也会更快?因为那是我的特定用例。
  • 如果 Chrome 仍在使用 V8(ISTR 是吗?),那么来自 Chrome 的结果应该外推到 V8。
【解决方案3】:

问题是长度的计算。在此示例中,for(var i=0; i&lt;arr.length; i++){ } 语句 arr.length 将在每次循环迭代时计算。但是for(var i=0, l=arr.length; i&lt;l; i++){ } 的值将在没有任何计算的情况下被采用。简单地获取一个值比计算数组的长度要快。
任何编译器都无法优化获取长度,因为它可以更改。所以每次迭代都会计算。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-07-20
    • 1970-01-01
    • 2021-01-21
    • 2017-02-18
    相关资源
    最近更新 更多