【问题标题】:What Makes the Code Faster是什么让代码更快
【发布时间】:2014-06-16 00:40:59
【问题描述】:

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

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

I put them in 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 ops/sec 到 114,370,808 ops/sec 实际上非常重要。

【问题讨论】:

  • 为什么你认为缓存的版本会变慢?你想测试什么样的调用?
  • @Bergi - 我希望缓存版本会更慢,因为它必须将更多数据写入内存。
  • 但仅适用于第一次调用!当运行大约一百万次时(jsperf 告诉你每个测试循环的时间很长),这完全无关紧要。现在比较一个数组访问与 10 个函数调用。
  • 另外,您能否将其他测试用例与无意义的control 函数联系起来?
  • @Bergi - “无意义”是什么意思?

标签: javascript performance memoization


【解决方案1】:

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

【讨论】:

  • 您说得对,浏览器已经优化了代码,但是通过将1 更改为control(n) 来快速修改控制功能仍然会产生更快的计算。
  • 有或没有分配?这可能会导致非常不同的字节码。
【解决方案2】:

小心性能测试,通常在一台主机上速度更快的主机在另一台主机上速度较慢。

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

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

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

键入更多,但性能优势显着。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-18
    • 1970-01-01
    • 1970-01-01
    • 2020-03-05
    • 1970-01-01
    • 1970-01-01
    • 2022-11-11
    相关资源
    最近更新 更多