9

我在搞乱基准站点jfprefs并在http://jsperf.com/prefix-or-postfix-increment/9创建了我自己的基准。

基准是 Javascript for 循环的变体,使用前缀和后缀增量器以及不使用就地增量器的 Crockford jslint 样式。

for (var index = 0, len = data.length; index < len; ++index) {
  data[index] = data[index] * 2;
}

for (var index = 0, len = data.length; index < len; index++) {
  data[index] = data[index] * 2;
}

for (var index = 0, len = data.length; index < len; index += 1) {
  data[index] = data[index] * 2;
}

在从几次基准测试中获得数据后,我注意到 Firefox 平均每秒执行大约 15 次操作,而 Chrome 大约每秒执行 300 次。

基准测试结果

我认为 JaegerMonkey 和 v8 在速度方面相当可比?我的基准测试是否存在某种缺陷,Firefox 是否在这里进行了某种节流,或者 Javascript 解释器的性能之间的差距真的那么大吗?

更新:感谢jfriend00,我已经得出结论,性能差异并不完全是由于循环迭代,正如在这个版本的测试用例中看到的那样。如您所见,Firefox 速度较慢,但​​没有我们在初始测试用例中看到的差距那么大。

那么为什么是这样的说法,

data[index] = data[index] * 2;

Firefox 这么慢?

4

2 回答 2

8

数组在 JavaScript 中很棘手。创建它们的方式,填充它们的方式(以及使用什么值)都会影响它们的性能。

引擎使用两种基本实现。最简单、最明显的一种是连续的内存块(就像一个 C 数组,带有一些元数据,比如长度)。这是最快的方式,理想情况下是您在大多数情况下想要的实现。

问题是,JavaScript 中的数组可以通过分配给任意索引而变得非常大,从而留下“漏洞”。例如,如果您有一个小数组:

var array = [1,2,3];

并为大索引分配一个值:

array[1000000] = 4;

你最终会得到一个这样的数组:

[1, 2, 3, undefined, undefined, undefined, ..., undefined, 4]

为了节省内存,大多数运行时将转换array为“稀疏”数组。基本上,一个哈希表,就像普通的 JS 对象一样。一旦发生这种情况,对索引的读取或写入就会从简单的指针算术变为更复杂的算法,可能使用动态内存分配。

当然,不同的运行时使用不同的启发式方法来决定何时从一种实现转换为另一种实现,因此在某些情况下,针对 Chrome 进行优化可能会损害 Firefox 的性能。

在您的情况下,我最好的猜测是向后填充数组会导致 Firefox 使用稀疏数组,从而使其变慢。

于 2012-09-08T23:57:39.883 回答
-5

我不想给你这么简单的答案,但很简单:指令分支:http: //igoro.com/archive/fast-and-slow-if-statements-branch-prediction-in-modern-processors/

从我从基准测试中得到的信息来看,这些引擎的内部有些东西提供了处理器地狱的指令预测功能。

于 2012-09-08T06:03:29.960 回答