是什么让代码更快?

What Makes the Code Faster

本文关键字:代码 是什么      更新时间:2023-09-26

最初我是在测试添加一些缓存结果的代码将如何影响初始计算时间。我创建了一个简单的递归函数来计算阶乘:

function fac(n){
    return n <= 1 ? 1 : fac(n-1) * n;
}

然后我添加缓存结果以供以后使用的部分:

var f = [];
function fac(n){
     return n <= 1 ? 1 : f[n] ? f[n] : f[n] = fac(n-1) * n;
}

我把它们放在jsPerf中,结果是带缓存的版本出乎意料地快。我怀疑这可能是因为我使用的数组f在测试运行器中保持不变。该函数只是从数组中获取值,因此速度更快。

为了测试,我创建了另一个函数,它只返回数组中的值:
var test = []; test[10] = 3628800;
function control(n){
    return n <= 1 ? 1 : test[n] ? test[n] : 1;
}

结果表明控件比添加了缓存的函数要快得多。所以结论是:

  1. 数组f保持不变,ops/sec的差异是由初始计算引起的

  2. 数组f每次都被"重置",并且由于某种原因它比正常版本更快。

我不相信最初的计算会使整个测试比控制慢74%,因此#2应该是正确的。但是是什么让它比普通版本更快呢?从15,262,318次/秒到114,370,808次/秒,这是非常显著的

我怀疑control优化得这么好是因为它没有工作。快速查看一下就会发现它只有2个可能的返回值:test[10]1。由于您从未在函数中向test添加任何内容,因此它可能被优化到几乎为零。

要小心性能测试,通常在一个主机上更快的东西在另一个主机上更慢。

如果你真的关心速度,不要使用递归,因为顺序循环在所有主机中几乎总是明显更快。阶乘函数通常用于递归示例,因为它与非递归函数相比更容易理解和比较,而不是因为它更快。

使用带有存储结果的循环函数应该是所有函数中最快的:

var factorial = (function () {
  var facStore = [1,1,2];
  return function (n) {
    var x = n;
    var result = 1;
    if (n == 0 || facStore[n]) return facStore[n];
    while (n) result = result * n--;
    facStore[x] = result;
    return result;
  } 
}());

这是更多的类型,但性能优势是显著的。