为什么多个内联IF比每个数组条目有一个IF的循环更快

时间:2017-04-07 14:15:49

标签: javascript v8

Angular有以下有趣的function implementation,它不是循环遍历值数组,而是将它们作为参数并执行if内联检查。我认为它是出于性能目的而完成的,所以我创建了this simple performance test

function checkAndUpdateTextInline(v, def, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9) {
    let changed = false;
    const bindings = def.bindings;
    const bindLen = bindings.length;

    if (bindLen > 0 && checkAndUpdateBinding(v, def, 0, v0)) changed = true;
    if (bindLen > 1 && checkAndUpdateBinding(v, def, 1, v1)) changed = true;
    if (bindLen > 2 && checkAndUpdateBinding(v, def, 2, v2)) changed = true;
    if (bindLen > 3 && checkAndUpdateBinding(v, def, 3, v3)) changed = true;
    if (bindLen > 4 && checkAndUpdateBinding(v, def, 4, v4)) changed = true;
    if (bindLen > 5 && checkAndUpdateBinding(v, def, 5, v5)) changed = true;
    if (bindLen > 6 && checkAndUpdateBinding(v, def, 6, v6)) changed = true;
    if (bindLen > 7 && checkAndUpdateBinding(v, def, 7, v7)) changed = true;
    if (bindLen > 8 && checkAndUpdateBinding(v, def, 8, v8)) changed = true;
    if (bindLen > 9 && checkAndUpdateBinding(v, def, 9, v9)) changed = true;

    return changed;
}

与动态版:

function checkAndUpdateTextDynamic(v, def, values) {
    const bindings = def.bindings;
    let changed = false;
    for (let i = 0; i < values.length; i++) {
        if (checkAndUpdateBinding(v, def, i, values[i])) {
            changed = true;
        }
    }
}

内联版似乎比动态快25%。可能是什么原因? inline caching在这里玩吗?如何使用d8调试它?

2 个答案:

答案 0 :(得分:4)

首先,这两个版本不相同:迭代次数在第一个版本中由bindings.length界定,在第二个版本中由values.length界定。如果它们不同,您可能会得到不同的迭代次数。

其次,展开版本有几个操作可以避免:

  • 每次迭代都获得values.length
  • 在每次迭代时访问values[i]
  • 每次迭代都会阅读i
  • 每次迭代都会增加i
  • 每次迭代都跳回到循环的开头。

前两个特别昂贵,具体取决于编译器能够执行的动态优化和专业化的数量。如果checkAndUpdateBinding做得不多,那可能是一个明显的开销。您可以尝试更改原始版本以使用其中一些操作,并查看将其放在比较中的位置。

第三,这是一个微观基准。 JavaScript中的性能涉及如此多的隐藏变量以及对静态和动态上下文的依赖性,微基准测试比其他语言更无意义。总的来说,我估计人们对jsperf测量的内容中有90%是无用的,甚至是误导性的。

第四,请注意,循环展开是编译器执行的相当常见的优化。在某些情况下,即使在比JavaScript更有效的语言中,它也可能是一个重要的胜利。

答案 1 :(得分:1)

没有循环,就不需要更新或比较i(它不存在)。使用Array.prototype.length时,某些实现可能会很慢。

优化器也可以使用展开的版本,因为它具有固定数量的步骤。优化器不知道values是1项,10项,100项还是1000万项。