为啥向后迭代数组比向前迭代更快
Posted
技术标签:
【中文标题】为啥向后迭代数组比向前迭代更快【英文标题】:Why is iterating through an array backwards faster than forwards为什么向后迭代数组比向前迭代更快 【发布时间】:2012-01-31 03:40:30 【问题描述】:鉴于此代码:
var arr = [];
for (var i = 0; i < 10000; ++i)
arr.push(1);
转发
for (var i = 0; i < arr.length; ++i)
向后
for (var i = arr.length - 1; i >= 0; --i)
硬编码转发
for (var i = 0; i < 10000; ++i)
为什么倒退这么快?
这是测试: http://jsperf.com/array-iteration-direction
【问题讨论】:
请注意,您的后向案例应从arr.length-1
开始,并使用 i >= 0
而不是 i > 0
。
标题具有误导性。不再是直接使用 arr.length 在高级浏览器中变慢了。
javascript loop performance - Why is to decrement the iterator toward 0 faster than incrementing的可能重复
【参考方案1】:
因为在第一种形式中,您每次迭代都访问数组arr
的属性length
一次,而在第二种形式中您只访问一次。
【讨论】:
@samccone - 您看到了什么结果(在哪个浏览器中进行了哪个测试)?我看到缓存长度总是至少一样快,而且通常更快。 好吧,你是对的......看起来它确实是一个混合的结果,但缓存确实有帮助......谢谢XD【参考方案2】:i > 0
比 i < arr.length
快,并且在循环的每次迭代中都会发生。
您可以通过以下方式减轻差异:
for (var i = 0, len = arr.length; i < len; ++i) ;
这仍然不如向后项目快,但比您的向前选项快。
【讨论】:
看看硬编码测试jsperf.com/array-iteration-direction ...使用你的逻辑应该更快不是吗?【参考方案3】:如果你想让它们保持相同的速度,你可以这样做进行前向迭代;
for(var i=0, c=arr.length; i<c; i++)
因此,您的脚本不需要在每一步都获取数组的长度。
【讨论】:
啊……有趣的是,您的方法现在获得了最快迭代的桂冠jsperf.com/array-iteration-direction【参考方案4】:这些同样好:
var arr= [], L= 10000;
while(L>-1) arr[L]= L--;
或
var arr= [], i= 0;
while(i<10001) arr[i]=i++;
【讨论】:
应该是while(--L>=0) arr[L] = L;
【参考方案5】:
我对此并不完全确定,但这是我的猜测:
对于以下代码:
for (var i = 0; i < arr.length; ++i) ;
在运行期间,每次循环通过后都会进行 arr.length 计算。当它独立时,这可能是一个微不足道的操作,但在涉及多个/巨大的数组时可能会产生影响。您可以尝试以下方法吗:
var numItems = arr.length;
for(var i=0; i< numItems; ++i)
在上面的代码中,我们只计算了一次数组长度,并使用计算出的数字进行操作,而不是一遍又一遍地执行长度计算。
再一次,把我的想法放在这里。确实很有趣的观察!
【讨论】:
【参考方案6】:像下面那样做,它会以同样的方式执行。因为arr.length
在向前的每次迭代中都需要时间。
int len = arr.length;
前进
for (var i = 0; i < len; ++i)
向后
for (var i = len; i > 0; --i)
【讨论】:
后面的情况是不对的。我所做的是for(i=len; --i>=0;)
for (let i = arr.length; i-- > 0;)
【参考方案7】:
因为您的转发条件每次都必须接收数组的 length
属性,而另一个条件只需要检查“大于零”,这是一项非常快的任务。
当你的数组长度在循环期间没有改变,并且你真的看 ns-perfomance 时,你可以使用
for (var i=0, l=arr.length; i<l; i++)
顺便说一句:您可以使用for (var i = arr.length; i-- > 0; )
而不是for (var i = arr.length; i > 0; --i)
,它实际上是从n-1 到0,而不是从n 到1。
【讨论】:
是的,这就是我优化功能的方式。请注意,如果数组是可变的(通常不是),这可能会跳过一两个资源。例如,如果您正在循环遍历循环本身正在添加或删除的元素,这将不起作用。 你甚至可以做for(... ; i-- ;)
所以基本上这意味着如果我不更改数组并将array.length保存在一个变量中,那么向后速度=向前速度?示例: var length = array.length; for(var i = 0 ; ii<l
是与 i>0
不同的计算,但是它们相当相等(比未缓存的长度更快):jsperf.com/array-iteration-direction/3 - 但有些引擎确实识别并优化了其中一些案例
快进到 2018 年。看起来现代版本的浏览器不会使循环变慢,即使在每次迭代中访问 arr.length 时(您的转发案例)以上是关于为啥向后迭代数组比向前迭代更快的主要内容,如果未能解决你的问题,请参考以下文章
有没有比使用 np.where 更快的方法来迭代一个非常大的 2D numpy 数组?
为啥在迭代 NumPy 数组时 Cython 比 Numba 慢得多?