如果更频繁地执行,相同的代码需要更长

时间:2012-01-14 12:59:45

标签: javascript iteration execution-time

我在网页上的<script>标记内有以下代码,上面没有任何其他内容。我恐怕我现在没有上网。正如您所看到的,它以两种不同的方式将所有素数低于200万,并计算平均花费的时间。变量howOften用于执行此操作多次,因此您可以对其进行平均。让我感到困惑的是,对于howOften == 1,方法2更快,但对于howOften == 10,方法1更快。即使你多次击中F5,这种差异也很显着。

我的问题很简单:怎么回事?

(这篇文章已被编辑,以纳入alf的建议。但这没有任何区别!我现在非常困惑。)

(再次编辑:howOften等于或超过1000,时间似乎稳定.Alf的回答似乎是正确的。)

function methodOne(maxN) {
    var sum, primes_inv, i, j;

    sum = 0;
    primes_inv = [];
    for ( var i = 2; i < maxN; ++i ) {
        if ( primes_inv[i] == undefined ) {
            sum += i;
            for ( var j = i; j < maxN; j += i ) {
                primes_inv[j] = true;
            }
        }
    }
    return sum;
}

function methodTwo(maxN) {
    var i, j, p, sum, ps, n;

    n = ((maxN - 2) / 2);
    sum = n * (n + 2);
    ps = [];
    for(i = 1; i <= n; i++) {
        for(j = i; j <= n; j++) {
            p =  i + j + 2 * i * j;
            if(p <= n) {
                if(ps[p] == undefined) {
                    sum -= p * 2 + 1;
                    ps[p] = true;
                }
            }
            else {
                break;
            }
        }
    }
    return sum + 2;
}



// ---------- parameters
var howOften = 10;
var maxN = 10000;

console.log('iterations: ', howOften);
console.log('maxN: ', maxN);


// ---------- dry runs for warm-up
for( i = 0; i < 1000; i++ ) {
    sum = methodOne(maxN);
    sum = methodTwo(maxN);
}

// ---------- method one
var start = (new Date).getTime();

for( i = 0; i < howOften; i++ )
    sum = methodOne(maxN);

var stop = (new Date).getTime();
console.log('methodOne: ', (stop - start) / howOften);

// ---------- method two

for( i = 0; i < howOften; i++ )
    sum = methodTwo(maxN);

var stop2 = (new Date).getTime();
console.log('methodTwo: ', (stop2 - stop) / howOften);

2 个答案:

答案 0 :(得分:2)

嗯,JS运行时是一个优化的JIT编译器。这意味着有一段时间,你的代码被解释(t int ),之后,它被编译(t jit ),最后你运行一个编译的代码(t <子>运行)。

现在你计算的很可能是(t int + t jit + t run )/ N.鉴于N上几乎线性依赖的唯一部分是t run ,不幸的是,这种比较没有多大意义。

所以答案是,我不知道。要有一个正确的答案,

  1. 将您要分析的代码解压缩为函数
  2. 在这些功能上运行预热周期,使用预热周期中的时间
  3. 运行时间超过1..10次,用于预热和测量
  4. 尝试交换您测量算法时间的顺序
  5. 如果可以,请进入JS解释器内部,并确保您了解会发生什么:您是否真的衡量您的想法? JIT是在预热周期中运行而不是在测量时运行吗?等等。
  6. 更新:另请注意,在1个周期内,您的运行时间会低于系统计时器的分辨率,这意味着错误可能比您比较的实际值大。

答案 1 :(得分:0)

methodTwo只需要处理器执行较少的计算。在methodOne中,您的初始for循环正在执行maxN次。在methodTwo中,您的初始for循环正在执行(maxN -2)/ 2次。因此,在第二种方法中,处理器所执行的计算数量不到第一种方法的一半。事实上,每个方法都包含一个嵌套的for循环。所以methodOne的大O是maxN ^ 2。而方法二的大O是((maxN -2)/ 2)^ 2。