我应该将Performance.now()调用放在哪里?

时间:2018-07-24 15:02:09

标签: javascript performance

我写了一个小脚本来按执行时间比较函数的实现。例如,它运行一个functon函数1e6次,并对每个调用的执行时间求和。我不知道应该将performance.now()调用放在什么位置。第一种选择是在函数调用之前和之后将它们放入for循环中,然后在每次迭代后仅对结果求和。第二种选择是将performance.now()调用放在循环本身之前和之后。第一种情况感觉更准确,但在我的机器上,最终结果稳定地比第二种情况大30%。有人可以向我解释为什么吗? performance.now()的正确位置是什么?

第一个选项-performance.now()在循环内调用。在我的计算机上计算150个1e6的阶乘大约需要1300毫秒:

function factorial(x) {
    return x === 1 ? 1 : x * factorial(x - 1); 
}

function measure(func, arg, times) {
  let timeSpent = 0;
  for(var i = times;i--;) {
      let t1 = performance.now();   
      func(arg);
      let t2 = performance.now();
      timeSpent += t2 - t1;
  }
  console.log(`Tested function ${func.name} has been executed ${times} times with argument ${arg} and it has taken %d ms. in total.`, timeSpent);
}

measure(factorial, 150, 1e6);

第二个选项-performance.now()在循环之外调用。在我的计算机上计算150个1e6的阶乘大约需要1000毫秒:

    function factorial(x) {
        return x === 1 ? 1 : x * factorial(x - 1); 
    }

    function measure(func, arg, times) {
      let t1 = performance.now();
      for(var i = times;i--;) func(arg);
      let t2 = performance.now();
      console.log(`Tested function ${func.name} has been executed ${times} times with argument ${arg} and it has taken %d ms. in total.`, t2 - t1);
    }

    measure(factorial, 150, 1e6);

1 个答案:

答案 0 :(得分:0)

进行性能评估时,我会考虑以下几点:

  • 我正在使用的 time 服务的准确性是什么,它返回的是“壁钟时间”还是“ cpu时间”

  • 我需要从测量中获得什么精度(1%、. 1%,10%?)

  • 我想花多少时间进行性能测试?

  • 在进行评估之前我是否需要“热身时间”(例如,如果我正在评估事务运行所需的时间,并且我使用的是Java或javascript之类的JITted语言,那么我可能想放弃前N个结果的时间。另一方面,如果我正在测量一个“批处理”程序-某个程序只运行一次-则不需要这样做。

通常,时间服务的精度介于数百微秒到几毫秒之间。所以-您想确保自己在所测量的内容周围进行足够的循环,以免您担心时间功能引起麻烦。因此,如果我有一个精确到(例如)100us的计时器,那么我将确保我运行了足够多的循环,以花费至少1000us(1ms)甚至10ms。

在进行性能测量时,还有很多原因会导致抖动。抖动是您在进行性能测量时在实践中不可避免的可变性。所以-我还要重复执行几次性能测试,并查看这些测试的均值,标准差,以查看结果的一致性(这也有助于阐明JIT编译器之类的东西,因为当您查看时会发现一些非常离群的异常值根据您的结果)。

要真正回答您的问题,我将选择您的第二个选择。您想确保已完成足够的工作,以确保时间服务的准确性不成问题。