为啥在 for 循环之后比 for 循环之前慢得多?

Posted

技术标签:

【中文标题】为啥在 for 循环之后比 for 循环之前慢得多?【英文标题】:Why is let much slower after a for loop than before a for loop?为什么在 for 循环之后比 for 循环之前慢得多? 【发布时间】:2017-01-29 03:15:25 【问题描述】:

在 node.js v6.0.0 中

function testlet() 
	let a = 0;
	for (var i = 0; i < 100000000; i++) 


function testlet2() 
	for (var i = 0; i < 100000000; i++) 
	let a = 0;


console.time('let');
testlet();
console.timeEnd('let'); 

console.time('let2');
testlet2();
console.timeEnd('let2'); 

let在代码中的位置怎么会造成这么大的性能差异?

【问题讨论】:

在 chrome 中效果相同(不出意外) - 在其他浏览器中没有这种差异 const 也会发生这种情况,但var 两者的速度相同。 虽然很奇怪,但我建议不要太担心它。微优化是一个移动的目标。今天快的东西明天很容易变慢。 测试下:node.js和chrome浏览器性能不同,firefox一样,比v8快。 safari 不支持 let 你能发布你得到的结果吗? 【参考方案1】:

我会做出有根据的猜测,并说temporal dead zone 是罪魁祸首。

那个循环,这似乎是你的微基准测试的内容,是eaten by the optimiser for breakfast,就像 Vyacheslav Egorov likes to put it 在他的谈话中一样。即使不是这样,引擎也会将变量递增一百万次,这两个函数的时间都相同。

不同的是创建变量a 的时间。在您的第一个 sn-p 中,它位于函数的开头,之前没有任何内容。没有时间死区,它本质上是一个函数范围的变量;将其更改为 var 不会有什么不同(试试看)。因此,当调用该函数时,将创建具有变量的范围并将值初始化为0,然后运行(或不运行)一些代码。 相反,在第二个 sn-p 中有一个时间死区。在let 声明之前的代码中,访问a 必须抛出异常。因此,当调用该函数时,将创建范围并为a 保留一个插槽,但未初始化。在这种状态下,代码运行(或不运行),只有在此之后,变量才会被初始化并赋值为0

因此,如果let 位于代码中间(或代码之后),则作用域会更加复杂。这可能会导致优化器对其进行不同的处理,甚至可能会影响同一范围内的变量i,或者可能根本无法进行某些优化。

【讨论】:

以上是关于为啥在 for 循环之后比 for 循环之前慢得多?的主要内容,如果未能解决你的问题,请参考以下文章

为啥以下简单的并行化代码比 Python 中的简单循环慢得多?

为啥 memcmp 比 for 循环检查快得多?

比 LLVM 中的 floor/ceil/int 慢得多

arrayfun 可能比 matlab 中的显式循环慢得多。为啥?

在 AIX/bash 上的 bash 循环中读取文件比在 Linux/ksh 中慢得多 - BLOCKSIZE?

为啥在迭代 NumPy 数组时 Cython 比 Numba 慢得多?