小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

漫談遞歸:PHP里的尾遞歸及其優(yōu)化

 herowuking 2015-10-10

不同的語(yǔ)言對(duì)尾遞歸的支持都有所不同,編譯器的優(yōu)化也不盡相同。我們之前看了C語(yǔ)言的尾遞歸,那么在PHP里又是如何的呢?

PHP對(duì)尾遞歸沒(méi)有優(yōu)化效果

先來(lái)看下實(shí)驗(yàn)。

01<?php
02function factorial($n)
03{
04    if($n == 0) {
05        return 1;
06    }  
07    return factorial($n-1) * $n;
08}
09  
10var_dump(factorial(100));
11?>

如果安裝了XDebug的話,可能會(huì)遇到如下錯(cuò)誤:

1Fatal error: Maximum function nesting level of '100' reached, aborting!

這是XDebug的一個(gè)保護(hù)機(jī)制,可以通過(guò)max_nesting_level選項(xiàng)來(lái)設(shè)置。放開(kāi)設(shè)置的話,程序還是能夠正常運(yùn)行的。

即便代碼能正常運(yùn)行,只要我們不斷增大參數(shù),程序遲早會(huì)報(bào)錯(cuò):

1Fatal error:  Allowed memory size of … bytes exhausted

為什么呢?簡(jiǎn)單點(diǎn)說(shuō)就是遞歸造成了棧溢出。按照之前的思路,我們可以試下用尾遞歸來(lái)消除遞歸對(duì)棧的影響,提高程序的效率。

01<?php
02function factorial($n, $acc)
03{
04    if($n == 0) {
05        return $acc;
06    }
07    return factorial($n-1, $acc * $n);
08}
09 
10 
11var_dump(factorial(100, 1));
12?>

XDebug同樣報(bào)錯(cuò),并且程序的執(zhí)行時(shí)間并沒(méi)有明顯變化。

1Fatal error: Maximum function nesting level of '100' reached, aborting!

事實(shí)證明,尾遞歸在php中是沒(méi)有任何優(yōu)化效果的。

PHP如何消除遞歸

先看看下面的源代碼:

01<?php
02function factorial($n, $accumulator = 1) {
03    if ($n == 0) {
04        return $accumulator;
05    }
06 
07    return function() use($n, $accumulator) {
08        return factorial($n - 1, $accumulator * $n);
09    };
10}
11 
12function trampoline($callback, $params) {
13    $result = call_user_func_array($callback, $params);
14 
15    while (is_callable($result)) {
16        $result = $result();
17    }
18 
19    return $result;
20}
21 
22var_dump(trampoline('factorial', array(100)));
23 
24?>

現(xiàn)在XDebug不再警報(bào)效率問(wèn)題了。

注意到trampoline()函數(shù)沒(méi)?簡(jiǎn)單點(diǎn)說(shuō)就是利用高階函數(shù)消除遞歸。想更進(jìn)一步了解 call_user_func_array,可以參看這篇文章:PHP函數(shù)補(bǔ)完:call_user_func()與call_user_func_array()

還有很多別的方法可以用來(lái)規(guī)避遞歸引起的棧溢出問(wèn)題,比如說(shuō)Python中可以通過(guò)裝飾器和異常來(lái)消滅尾調(diào)用,讓人有一種別有洞天的感覺(jué)。

小結(jié)

在C中的尾遞歸優(yōu)化是gcc編譯器做的。一般的線性遞歸修改成為尾遞歸最大的優(yōu)勢(shì)在于減少了遞歸調(diào)用棧的開(kāi)銷。從php那個(gè)例子就明顯看出來(lái)遞歸開(kāi)銷對(duì)程序的影響。但是并不是所有語(yǔ)言都支持尾遞歸的,即使支持尾遞歸的語(yǔ)言也一般是在編譯階段對(duì)尾遞歸進(jìn)行優(yōu)化,比如C語(yǔ)言對(duì)尾遞歸的優(yōu)化。在使用尾遞歸對(duì)代碼進(jìn)行優(yōu)化的時(shí)候,必須先了解這門(mén)語(yǔ)言對(duì)尾遞歸的支持。

在PHP里,除非能提升代碼可讀性,否則沒(méi)有必要使用遞歸;迫不得已之時(shí),最好考慮使用Tail Call或Trampoline等技術(shù)來(lái)規(guī)避潛在的棧溢出問(wèn)題。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多