加快javascript中的递归函数

时间:2015-06-01 13:34:01

标签: javascript recursion

有没有办法加快执行这个递归函数并保持递归?

var printDecreased = function(z) {
    console.log(z);

    if (z > 0) {
        printDecreased(z-1);
    }
};

printDecreased(50);

由于这只有一个递归调用,我认为有很多方法可以加速它

4 个答案:

答案 0 :(得分:2)

加速功能的一种可能方法是为其添加一点冗余。例如,使用Duff's device我们可以尝试提高函数的性能:

function printDecreasedOptimized(z) {
    console.log(z);

    if (z > 0) {
        switch (z % 8) {
        case 0: console.log(--z);
        case 7: console.log(--z);
        case 6: console.log(--z);
        case 5: console.log(--z);
        case 4: console.log(--z);
        case 3: console.log(--z);
        case 2: console.log(--z);
        case 1: console.log(--z);
        }

        (z > 0 && printDecreasedDuff(z));
    }
}

function printDecreasedDuff(z) {
    console.log(--z);
    console.log(--z);
    console.log(--z);
    console.log(--z);
    console.log(--z);
    console.log(--z);
    console.log(--z);
    console.log(--z);

    (z > 0 && printDecreasedDuff(z));
}

这个想法是一次执行八次迭代,从而节省了七个函数调用开销的成本。令人惊讶的是,on benchmarking this code我发现这种优化对性能没有太大影响。

我猜测像V8和SpiderMonkey这样的现代JavaScript引擎足够聪明,可以优化这些递归函数。因此,您无需担心此类功能的性能。确实,premature optimization is the root of all evil

BTW,在proper tails calls附近,您的递归函数只会变得更快。

答案 1 :(得分:1)

你可以通过避免if语句来增加速度:

var printDecreased = function(z) {
    console.log(z);

    (z > 0 && printDecreased(z-1));
};

printDecreased(50);

但增幅很小(约5-10%)

这是如何运作的?

这里的关键字是分支预测。我不会详细介绍分支预测,因为这不是问题所在。最重要的是,分支机构花费了相当多的CPU时间,这意味着,每个如果非常昂贵,如果你想提高大量使用线路的速度,那么尽量省去所有分支机构

最简单的方法是替换 if / else 构造,每个构造只包含三元运算符,而 if 构造只包含一个语句总计由&& || 运算符组成。这些通常比 if s或 if / else 更快。这几乎适用于任何支持这些结构的编程语言。

<强>实施例

if (x==y) {
    callA();
} else {
    callB();
}

可以替换为

(x==y ? callA() : callB());

if (x==y) {
    callA();
}

可以替换为

(x==y && callA());

(x!=y || callA());

这些选项为编译器提供了更好的优化方法,因此可以优化分支预测。

其他可能的优化 到目前为止,这个例子很难被优化,具有给定的限制。由于这是一个微不足道的函数,函数调用开销构成了执行时间的很大一部分。如果你可以用循环替换递归(这在给定的例子中很容易完成),一般来说,你可以加快这个过程的速度。删除递归可以加速大多数编程语言中的函数,因为调用函数通常会花费大量的CPU时间。

答案 2 :(得分:-1)

您可以查看memoize。 Underscore声称它是Useful for speeding up slow-running computations

答案 3 :(得分:-1)

简单地缩短了功能名称。在...创建了一个性能测试 jsperft

var p = function(z) {
    console.log(z);

    (z > 0 && p(z-1));
};
相关问题