我听过这个问题很多次。JavaScript 循环倒序计数真的更快吗?如果是这样,为什么呢?我看到一些测试套件示例显示反向循环更快,但我找不到任何解释为什么!
我猜这是因为循环不再需要每次评估一个属性来检查它是否完成,而只需针对最终数字值进行检查。
即:
for (var i = count - 1; i >= 0; i--)
{
// count is only evaluated once and then the comparison is always on 0.
}
我听过这个问题很多次。JavaScript 循环倒序计数真的更快吗?如果是这样,为什么呢?我看到一些测试套件示例显示反向循环更快,但我找不到任何解释为什么!
我猜这是因为循环不再需要每次评估一个属性来检查它是否完成,而只需针对最终数字值进行检查。
即:
for (var i = count - 1; i >= 0; i--)
{
// count is only evaluated once and then the comparison is always on 0.
}
它取决于数组在内存中的位置以及访问该数组时内存页面的命中率。
在某些情况下,按列顺序访问数组成员比按行顺序更快,因为会增加命中率。
Z
,表示“达到零”。因此,在循环结束时,您只需要执行两个指令:DEC
(递减)和JNZ
(如果不为零则跳转),无需比较!i--
而不是i++
可以避免在循环作用域中引入额外的控制变量。请参见下面的答案... - Pavel Pdec/jnz
而不是inc/cmp/jne
。你不会看到空循环运行得更快(两者都会饱和分支吞吐量),但是倒数计数略微减少了循环开销。当前的英特尔硬件预取器也不会受到以降序访问内存的模式的影响。旧的CPU可以追踪4个向后流和6或10个向前流,如果我没记错的话。 - Peter Cordes你现在的做法并不更快(除非你是想写一个无限循环,我猜你应该是想写 i--
)。
如果你想让它更快,可以这样做:
for (i = 10; i--;) {
//super fast loop
}
(i = 10; i--;)
- searleafor ( var i = 1; i <= array.length; i++ )
每次增加 i
时,你都会评估 .length
。在这个例子中:
for ( var i = 1, l = array.length; i <= l; i++ )
当你声明 i
时,只会计算一次 .length
。而在这个例子中:
for ( var i = array.length; i--; )
比较是隐式的,在递减i之前发生,代码非常易读。然而,让循环变得更加出色的是你在循环中放置的内容。
带有对函数的调用的循环(在其他地方定义):
for (i = values.length; i-- ;) {
add( values[i] );
}
嵌入代码的循环:
var sum = 0;
for ( i = values.length; i-- ;) {
sum += values[i];
}
这可以通过JavaScript(和所有语言)最终转换为操作码以在CPU上运行来解释。CPU始终有一个用于与零进行比较的单个指令,速度非常快。
另外,如果您可以保证count
始终>= 0
,则可以简化为:
for (var i = count; i--;)
{
// whatever
}
for(var i = array.length; i--; )
的速度并没有太大提升。但是,当你将array.length
替换成super_puper_function()
时,速度可能会显著提高(因为它在每次迭代中都被调用)。这就是区别所在。
如果您要在2014年更改它,您不需要考虑优化。如果您要使用“搜索和替换”更改它,则不需要考虑优化。如果您没有时间,您不需要考虑优化。但是现在,您有时间考虑它。
P.S.:i--
比i++
慢。
var a = array.length;
语句,这样你就不需要每次在循环中计算它的值但是你必须明白,你能获得的改进非常微不足道,大多数情况下你甚至不需要在意。
很久很久以前,有一种常见的机器指令,DSZ(递减并跳过零)。使用汇编语言编程的人们使用这个指令来实现循环以节省寄存器。现在这些古老的事实已经过时了,我非常确定你不会在任何语言中使用这个伪装的改进来提高性能。
我认为这种知识能够在我们这个时代传播的唯一方式是当你阅读别人的代码时。看到这样的结构并询问为什么要这样实现,答案是: "它可以与零进行比较,从而提高性能"。你惊讶于同事的高超知识,并想利用它变得更聪明 :-)
array.length
并不一定会产生性能损失,因为JS虚拟机足够聪明,可以找出数组是否被循环体修改。请参见下面的答案。 - Pavel P这不取决于--
或++
符号,而是取决于您在循环中应用的条件。
例如:如果变量具有静态值,则循环速度较快,而如果循环每次都检查条件(如数组长度或其他条件),则速度较慢。
但是不要担心这种优化,因为这次其效果只能以纳秒来衡量。
++
与--
在JavaScript中并不重要,因为JavaScript是一种解释性语言,而不是编译性语言。每个指令都会被翻译成多个机器语言,你不需要关心这些细节。
那些谈论使用--
(或++
)来有效利用汇编指令的人是错误的。这些指令适用于整数算术,而在JavaScript中没有整数,只有数字(链接到相关信息)。
你应该编写易读的代码。
for (var i = 0; i < myArray.length; i++) {...
for (var i = 0, var j = myArray.length; i < j; i++) {...
for (var i = myArray.length-1; i > -1; i--) {...
这段代码仍然只在开始时计算了数组的大小,但是我们现在将循环计数器与一个常量进行比较,而不是与变量进行比较。由于常量比变量更有效地访问,并且我们比之前少使用了一条语句,因此我们的第三个版本的代码现在比第二个版本稍微更高效,并且比第一个版本大大更高效。
for
循环更快,因为上界(嘿嘿,下界)循环控制变量不需要被定义或从对象中获取;它是一个常数零。 - Josh Stodola