简体   繁体   English

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

[英]Why are 100000 iterations of a for loop faster than 50000?

I've been working on this page to graph the performance of different aspects of javascript. 我一直在此页面上绘制javascript不同方面的性能图。 In the process of trying to graph a simple for loop at a varying number of iterations I've found that the speed of the loop seems to dramatically increase at some point over 50000 iterations and I am very interested to know why. 在尝试以不同的迭代次数绘制一个简单的for循环的过程中,我发现循环的速度似乎在超过50000次迭代的某个时刻显着增加,我非常想知道为什么。

Here's the loop I'm using: 这是我正在使用的循环:

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);
}

The value of test is n=1000000 in this picture 在这张照片中测试的值是n = 1000000

Obviously there are a lot of factors here, but this article from Chris Wilson at Google about how Chrome's two JIT compilers work may explain part of what you are seeing. 显然,有很多因素在这里,但这个文章从克里斯·威尔逊在谷歌关于Chrome的两位的JIT编译器是如何工作也许可以解释你所看到的一部分

In particular: 尤其是:

The Optimizing Compiler 优化编译器

In parallel with the full compiler, V8 re-compiles "hot" functions ( that is, functions that are run many times ) with an optimizing compiler. 与完整的编译器并行,V8使用优化的编译器重新编译“热”函数( 即,多次运行的函数 )。 This compiler uses type feedback to make the compiled code faster - in fact, it uses the types taken from ICs we just talked about! 该编译器使用类型反馈来加快编译后的代码的速度-实际上,它使用的是我们刚刚谈到的IC的类型!

In the optimizing compiler, operations get speculatively inlined (directly placed where they are called). 在优化的编译器中,操作以推测方式内联(直接放置在调用它们的位置)。 This speeds execution (at the cost of memory footprint), but also enables other optimizations. 这样可以加快执行速度(以内存占用为代价),但还可以进行其他优化。 Monomorphic functions and constructors can be inlined entirely (that's another reason why monomorphism is a good idea in V8). 单态函数和构造函数可以完全内联(这就是为什么单态性在V8中是个好主意的另一个原因)。

You can log what gets optimized using the standalone "d8" version of the V8 engine: 您可以记录使用V8引擎的独立“ d8”版本进行了优化的内容:

d8 --trace-opt primes.js

(this logs names of optimized functions to stdout.) Not all functions can be optimized, however - some features prevent the optimizing compiler from running on a given function (a "bail-out"). (这会将优化函数的名称记录到stdout。)但是,并非所有函数都可以被优化-一些功能会阻止优化编译器在给定函数上运行(“纾困”)。 In particular, the optimizing compiler currently bails out on functions with try {} catch {} blocks! 特别是, 优化编译器当前使用try {} catch {}块对函数进行救助!

So you can compare your original , with a version inside try {} catch {} blocks to prevent the optimizing compiler from interfering, and you will probably get a result closer to what you originally expected. 因此,您可以将您的原始 版本try {} catch {}块中版本进行比较,以防止优化编译器进行干扰,并且结果可能会更接近您的预期。

It's unclear from your question whether you fully understand statistics or the scientific method, so it may be that a quick recap will be useful. 从您的问题尚不清楚您是否完全了解统计信息或科学方法,因此快速回顾可能会很有用。 Apologies if you do understand, it may be a misapprehension on my part, but I think it's preferable to explain anyway, since the next person reading your question may gain valuable insight even if you don't. 道歉,如果您确实理解的话,那可能是我的误解,但是我认为还是最好还是进行解释,因为即使您不懂,下一个阅读您问题的人也可能会获得宝贵的见解。


Re statistics, unless you're basing your results on a relatively large sample size, the results cannot be relied upon, especially when the sort of timings you're examining (on the order of 1 / 10000 th of a second) can easily be swamped by a bit of "noise". 重新统计,除非你是在一个相对大样本基础你的结果,该结果不能依靠, 尤其是当那种你检查( 万分之一 秒的量级)定时可以很容易地充满了一些“噪音”。

For example, you may find that the computer you're testing it on with hit by a burst of activity by a different process when running the 50K test. 例如,当您运行50K测试时,您可能会发现正在测试的计算机由于活动异常而受到不同进程的冲击。

There are a number of ways to mitigate this issue, such as running with a lot more loops (so that any short-duration noise will have less of an impact), or running the test a great many times, averaging the results (for the same reason). 有很多方法可以缓解此问题,例如运行更多的循环(这样,任何短期噪声都会产生较小的影响),或者运行测试很多次,取平均结果(对于相同的原因)。


Re the scientific method, it's a good idea to perform experiments only changing one variable at a time: scientists use the phrase "all other things being equal" quite a bit and for good reason. 用科学的方法来说,最好一次只改变一个变量进行实验:科学家有充分的理由使用“所有其他条件都相同”这一短语。

What I'm getting at here is the possibility that your Javascript interpreter is, at some point, recognising that the code in the loop is being run a great many times and is therefore performing a JIT conversion on it. 我要说的是,您的Javascript解释器可能在某个时刻认识到循环中的代码正在运行很多次,因此正在对其执行JIT转换。

Chrome does do JIT compilation , containing a baseline JIT compiler which gets run on all code, and an optimising compiler which is more targeted but can produce far faster code. Chrome浏览器确实进行JIT编译 ,其中包含可在所有代码上运行的基准JIT编译器,以及针对性更强但可以产生更快代码的优化编译器。

To test that premise (that it's the JIT compiler), and assuming you're doing all the iteration sets in a single program run, you could reverse the order of them, or warm up the program by running a couple of 100K cycles first (throwing away the results). 要测试该前提(它是JIT编译器),并假设您在单个程序运行中完成所有迭代集,则可以颠倒它们的顺序,或者通过先运行两个100K周期来预热程序(扔掉结果)。

Here are the results from Chrome under Windows. 这是Windows下Chrome的结果。 The code is taken from: 该代码取自:

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));

with the order of the alert calls being the only thing changing. alert呼叫的顺序是唯一改变的事情。 The figures were extracted from ten separate runs and averaged to produce the below results. 这些数字是从十个单独的运行中提取的,取平均值即可得出以下结果。

With the alert calls in ascending order, we see something similar to you: 随着alert电话按升序排列,我们看到与您相似的内容:

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

Putting them in descending order in the source gives a slightly different view: 将它们按降序排列在源代码中会给出稍微不同的视图:

   500  0.00
  5000  0.02
 50000  0.79
500000  2.21

which is seemingly much more logical. 这似乎更加合乎逻辑。

I'd suggest running the same tests on your browser (or just reverse the order using your own test harness) to see if you have similar results. 我建议您在浏览器上运行相同的测试(或使用自己的测试工具颠倒顺序),看看是否有相似的结果。

I think you should try the same code more times. 我认为您应该多次尝试相同的代码。 I executed your code but get normal result.Try to let n be a bigger number, the inaccuracy of the test will be weakened. 我执行了您的代码,但得到了正常结果。尝试将n设为更大的数字,将会削弱测试的不准确性。 Moreover, your vacant loop can be optimized. 此外,您的空闲循环可以得到优化。 Please avoid making your loop nonsense. 请避免使循环变得毫无意义。 The browser is busy at the beginning of page loading, arranging doms worming up engines, etc. If you try to call this later the result maybe become normal. 浏览器正忙于页面加载的开始,安排了使引擎蠕动的域等等。如果稍后尝试调用此方法,则结果可能会正常。

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

When the same code is executed the second time, the procedure will be optimized by the browser. 第二次执行相同的代码时,浏览器将优化该过程。 So this time it may be slow, but will be faster in later times. 因此,这一次可能会很慢,但以后会更快。

Try something like this: 尝试这样的事情:

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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么Array(99999)比Array(100000)慢 - Why Array(99999) is slower than Array(100000) 为什么我的外部 for 循环执行的迭代次数超过了它应该执行的次数? - Why is my outer for-loop executing more iterations than it should? 为什么 lodash _.each 比原生 for 循环快? - Why is lodash _.each faster than the native for loop? 为什么 then 回调中的这个循环比异步 function 中的循环更快? - Why is this loop in a then callback faster than in an async function? 在JavaScript中,为什么“反向”循环比“for”快一个数量级? - In JavaScript, why is a “reverse while” loop an order of magnitude faster than “for”? JavaScript 循环性能 - 为什么将迭代器递减到 0 比递增更快 - JavaScript loop performance - Why is to decrement the iterator toward 0 faster than incrementing 在简单的循环测试中,Javascript比Classical C快100,为什么? - Javascript is 100 faster than Classical C in simple for loop test, why? 为什么递归比JavaScript上的求和函数的for循环更快? - Why is recursion faster than a flat for loop for a summation function on JavaScript? 为什么 if(1) 比 if(true) 快 - Why is if(1) faster than if(true) 我怎样才能使for循环的迭代速度快10 ^ 11次以上? - How can I make for loop with > 10^11 iterations faster?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM