【问题标题】:Loop optimization changing direction循环优化改变方向
【发布时间】:2017-01-31 14:59:27
【问题描述】:

我已阅读有关循环优化(N.Zakas,Javascript 优化)的信息。在那里,写到使用inverse loop for arrays 比直接循环更优化。这似乎完全合乎逻辑:

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

- 检查条件
- 增加变量i

for(i = length;i--;)

- 检查条件 + 增加变量 i(在一个表达式中)
但是,对于 Chrome,我得到了意想不到的结果。

var len = 100000000,
arr = new Array(len),
i = len - 1,
start = new Date(), 
end;

for(i = 0; i < len; i++){
    arr[i] = 1;
}

end = new Date();

console.log(end - start);

直接循环返回结果接近 4500 毫秒,但反向循环... 9500 毫秒!

为什么?

【问题讨论】:

  • "比直接循环更优化。" --- 这没什么意义。
  • N. Zakas 正在谈论展开循环和一种称为 Duffs Device -en.wikipedia.org/wiki/Duff%27s_device 的技术。使用while 循环,而不是for
  • 好的,在性能范围内说得更好
  • 你误读了 Zakas。基于jonraasch.com/blog/…,他的示例代码在更高效的版本中使用了do while循环,而不是for循环。
  • "对不起,这个陈述(关于向后循环)错了吗?" --- 它并不包含所有真相:迭代并不是真正的慢和应该优化的东西,而是你在循环体中所做的真正工作。换句话说 - 这就像说红色汽车比蓝色汽车快。

标签: javascript optimization


【解决方案1】:

for(i = length;i--;) 中的代码更少并不意味着要做的事情更少; i 仍然需要增加(或者在这种情况下,减少),并且仍然需要进行检查(之前是 i &lt; length,现在是 i != 0)。

我可能认为时间上的差异是由于for(i = 0; i &lt; length; i++) 是一个非常常见的构造,因此很容易优化(因此现代编译器/解释器有资源投入到显式优化这些)。但我承认这是猜测。

向后迭代可能会显示速度大大提高的一种情况是当您弹出数组的内容时:

for(i = 0; i &lt; arr.length; i++) arr.splice(i,1); 可能会从数组中删除第一个元素,并将所有其他元素向后移动以填充其引擎盖下的位置。

而:

for(i = arr.length; i--; ) arr.splice(i,1); 可能只需要在底层减少数组的长度(便宜得多!)。

我不确定这是否是您要进行的优化,但总结不是“向后迭代更快!”一般意义上的。

【讨论】:

    【解决方案2】:

    是的,iterating an array backwards can be faster。但这不是你在这里做的。您正在构造一个反向数组,这很奇怪(阅读:不太可能优化)。

    如果您首先开始分配最高索引,我猜该数组以稀疏数组开始,这比连续数组效率低得多。为此,赋值本身会变慢,或者一旦引擎意识到您在做什么,就会转换为普通数组。
    相反,如果您从0 开始,引擎可以根据需要增长数组,并从一开始就使用高效的内存表示。顺便说一句,我希望arr.fill(1) 更快。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-06-27
      • 2018-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-04
      • 2018-08-29
      • 2017-07-20
      相关资源
      最近更新 更多