为什么for循环的100000次迭代比50000快?

时间:2015-03-30 01:13:43

标签: javascript performance

我一直在这个页面上工作来绘制javascript不同方面的表现。在尝试以不同的迭代次数绘制一个简单的for循环的过程中,我发现循环的速度似乎在超过50000次迭代的某个点上急剧增加,我很有兴趣知道原因。

这是我使用的循环:

var oN = function (n)
{
    var startTime;
    var endTime;
    startTime = window.performance.now();
    for (var i = 0; i <= n; i++) {};
    endTime = window.performance.now() - startTime;
    return endTime.toFixed(2);
}

此图中测试值为n = 1000000

4 个答案:

答案 0 :(得分:6)

显然这里有很多因素,但Google的Chris Wilson关于Chrome的两个JIT编译器如何工作的this文章可以解释部分您所看到的内容。

特别是:

  

优化编译器

     

与完整编译器并行,V8使用优化编译器重新编译“热”函数(即多次运行的函数)。这个编译器使用类型反馈来使编译的代码更快 - 实际上,它使用了我们刚才谈到的IC类型!

     

在优化编译器中,操作以推测方式内联(直接放置在它们被调用的位置)。这加快了执行速度(以内存占用为代价),但也可以实现其他优化。单态函数和构造函数可以完全内联(这是为什么单态在V8中是一个好主意的另一个原因)。

     

您可以使用V8引擎的独立“d8”版本记录优化内容:

d8 --trace-opt primes.js

  

(这会将优化函数的名称记录到stdout。)   然而,并非所有函数都可以进行优化 - 某些功能会阻止优化编译器在给定函数上运行(“纾困”)。特别是,优化编译器目前使用try {} catch {}块来解决函数问题!

因此,您可以将originalversion inside try {} catch {} blocks进行比较,以防止优化编译器受到干扰,并且您可能会得到更接近您原先预期的结果。

答案 1 :(得分:4)

从您的问题中不清楚您是否完全了解统计数据或科学方法,因此快速回顾可能会有用。如果你明白道歉,这可能是我的误解,但我认为最好还是解释一下,因为即使你不这样做,下一个阅读你问题的人也可能获得宝贵的见解。 / p>


重新统计,除非您的结果基于相对较大的样本量,否则无法依赖结果,尤其是当您正在检查的时间排序时(< sup> 1 / 10000 th 一秒钟)很容易被一点“噪音”淹没。

例如,在运行50K测试时,您可能会发现正在测试它的计算机受到不同进程的一系列活动的影响。

有许多方法可以缓解这个问题,例如运行更多循环(以便任何短时噪音都会产生更少的影响),或者运行测试很多次,平均结果(出于同样的原因)。


重新采用科学方法,一次只更换一个变量进行实验是个好主意:科学家们使用“所有其他条件相同”这一短语并且有充分的理由。

我在这里得到的是,你的Javascript解释器在某种程度上可能会认识到循环中的代码运行了很多次,因此在它上面执行JIT转换。

Chrome does do JIT compilation,包含可在所有代码上运行的基线JIT编译器,以及更有针对性但可生成更快代码的优化编译器。

为了测试这个前提(它是JIT编译器),假设你在单个程序运行中执行所有迭代集,你可以颠倒它们的顺序,或者通过运行几个100K来预热程序首先循环(扔掉结果)。

以下是Windows下Chrome的结果。代码取自:

var oN = function (n)
{
    var startTime;
    var endTime;
    startTime = window.performance.now();
    for (var i = 0; i <= n; i++) {};
    endTime = window.performance.now() - startTime;
    return endTime.toFixed(2);
}

alert(oN(500000));
alert(oN(50000));
alert(oN(5000));
alert(oN(500));

alert次调用的顺序是唯一改变的事情。这些数据是从十次单独的运行中提取的,并取平均值得出以下结果。

按{1}}调用升序,我们会看到与您类似的内容:

alert

在源中按降序排列它们会产生略微不同的视图:

   500  0.02
  5000  0.08
 50000  0.80 \
500000  0.61 / strange behaviour here

这似乎更符合逻辑。

我建议您在浏览器上运行相同的测试(或者只是使用自己的测试工具反转订单),看看是否有类似的结果。

答案 2 :(得分:0)

我认为你应该多次尝试相同的代码。我执行了你的代码,但得到了正常的结果。试着让n成为一个更大的数字,测试的不准确性会被削弱。此外,您的空置循环可以进行优化。请避免让你的循环无稽之谈。浏览器在页面加载开始时很忙,安排doms蠕动引擎等。如果你稍后尝试调用它,结果可能会变得正常。

http://jsfiddle.net/87nt9gtg/3/

当第二次执行相同的代码时,浏览器将优化该过程。所以这次可能会很慢,但在以后会更快。

答案 3 :(得分:0)

尝试这样的事情:

var oN = function (iteration, n)
{
    var startTime;
    var endTime;
    var sum = 0;
    for (var i = 0; i < iteration; i++) {
        startTime = window.performance.now();
        for (var j = 0; j < n; j++) {
            var dummy = j * i;
        }
        sum += window.performance.now() - startTime;
    }
    return (sum / iteration).toFixed(2);
}