Javascript 为什么<;=慢于<;在V8中使用此代码段?
我正在阅读幻灯片,下面有一个类似代码的示例。我不明白为什么其他答案和评论提到两个循环之间的区别是第一个循环比第二个循环多执行一次迭代。这是真的,但在一个增加到25000个元素的数组中,一次迭代或多或少只会产生很小的差异。作为一个大概的猜测,如果我们假设平均长度增长为12500,那么我们可能预期的差异应该在1/12500左右,或者只有0.008% 这里的性能差异比一次额外的迭代所能解释的要大得多,并且在演示接近结束时解释了这个问题Javascript 为什么<;=慢于<;在V8中使用此代码段?,javascript,v8,Javascript,V8,我正在阅读幻灯片,下面有一个类似代码的示例。我不明白为什么其他答案和评论提到两个循环之间的区别是第一个循环比第二个循环多执行一次迭代。这是真的,但在一个增加到25000个元素的数组中,一次迭代或多或少只会产生很小的差异。作为一个大概的猜测,如果我们假设平均长度增长为12500,那么我们可能预期的差异应该在1/12500左右,或者只有0.008% 这里的性能差异比一次额外的迭代所能解释的要大得多,并且在演示接近结束时解释了这个问题 this.primes是一个连续数组(每个元素都有一个值),元素都
this.primes
是一个连续数组(每个元素都有一个值),元素都是数字
JavaScript引擎可以将这样一个数组优化为实际数字的简单数组,而不是碰巧包含数字但可能包含其他值或没有值的对象数组。第一种格式的访问速度要快得多:它需要更少的代码,而且数组要小得多,因此它更适合缓存。但是有一些条件可能会阻止使用这种优化格式
一种情况是缺少一些数组元素。例如:
let array = [];
a[0] = 10;
a[2] = 20;
现在a[1]
的值是多少?它没有价值。(说它的值未定义
,甚至都不正确——包含未定义
值的数组元素与完全缺失的数组元素不同。)
没有办法仅用数字来表示,因此JavaScript引擎被迫使用优化程度较低的格式。如果a[1]
像其他两个元素一样包含一个数值,那么该数组可能会被优化为一个数字数组
强制将数组转换为非优化格式的另一个原因是,如果您试图访问数组边界之外的元素,如演示文稿中所述
第一个循环具有
TL;DR较慢的循环是由于访问数组“越界”,这会迫使引擎以较少或甚至没有优化的方式重新编译函数,或者不以任何这些优化的方式编译函数(如果(JIT-)编译器在第一次编译“版本”之前检测到/怀疑此情况),阅读下面的原因;
有人不得不这么说(完全惊讶于没有人这么做):
曾经有一段时间,OP的代码片段会成为初学者编程书中的一个事实上的例子,旨在概述/强调javascript中的“数组”是从0开始索引的,而不是从1开始索引的,因此可以作为一个常见的“初学者错误”的例子(难道你不喜欢我如何避免使用“编程错误”;)
):越界数组访问
示例1:
使用基于0的索引(始终在ES262中)由5个元素组成的密集数组(连续(表示索引之间没有间隙),实际上每个索引处有一个元素)
因此,我们并不是在讨论
this.isPrimeDivisible = function(candidate) {
for (var i = 1; i < this.prime_count; ++i) {
if (candidate % this.primes[i] == 0) return true;
}
return false;
}
V8 version 7.3.0 (candidate)
time d8 prime.js
287107
12.71 user
0.05 system
0:12.84 elapsed
time d8 prime.js
287107
1.82 user
0.01 system
0:01.84 elapsed
let array = [];
a[0] = 10;
a[2] = 20;
var arr_five_char=['a', 'b', 'c', 'd', 'e']; // arr_five_char.length === 5
// indexes are: 0 , 1 , 2 , 3 , 4 // there is NO index number 5
function sum(arr){
var r=0, i=0;
for(;i<arr.length;) r+=arr[i++];
return r;
}
sum('abcde'); // String('0abcde')
sum([1,2,3]); // Number(6)
sum([1,,3]); // Number(NaN)
sum(['1',,3]); // String('01undefined3')
sum([1,,'3']); // String('NaN3')
sum([1,2,{valueOf:function(){return this.val}, val:6}]); // Number(9)
var val=5; sum([1,2,{valueOf:function(){return val}}]); // Number(8)
var iterations = 25000;
function Primes() {
this.prime_count = 0;
this.primes = new Array(iterations);
this.getPrimeCount = function() { return this.prime_count; }
this.getPrime = function(i) { return this.primes[i]; }
this.addPrime = function(i) {
this.primes[this.prime_count++] = i;
}
this.isPrimeDivisible = function(candidate) {
for (var i = 1; i <= this.prime_count; ++i) {
if ((candidate % this.primes[i]) == 0) return true;
}
return false;
}
};
function main() {
var p = new Primes();
var c = 1;
while (p.getPrimeCount() < iterations) {
if (!p.isPrimeDivisible(c)) {
p.addPrime(c);
}
c++;
}
console.log(p.getPrime(p.getPrimeCount() - 1));
}
main();
this.primes = new Array(iterations);
if ((candidate % this.primes[i]) == 0) return true;
for (var i = 1; i <= this.prime_count; ++i) {