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

分享

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

 herowuking 2015-10-10

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

PHP對尾遞歸沒有優(yōu)化效果

先來看下實驗。

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的話,可能會遇到如下錯誤:

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

這是XDebug的一個保護機制,可以通過max_nesting_level選項來設置。放開設置的話,程序還是能夠正常運行的。

即便代碼能正常運行,只要我們不斷增大參數(shù),程序遲早會報錯:

1Fatal error:  Allowed memory size of … bytes exhausted

為什么呢?簡單點說就是遞歸造成了棧溢出。按照之前的思路,我們可以試下用尾遞歸來消除遞歸對棧的影響,提高程序的效率。

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同樣報錯,并且程序的執(zhí)行時間并沒有明顯變化。

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

事實證明,尾遞歸在php中是沒有任何優(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不再警報效率問題了。

注意到trampoline()函數(shù)沒?簡單點說就是利用高階函數(shù)消除遞歸。想更進一步了解 call_user_func_array,可以參看這篇文章:PHP函數(shù)補完:call_user_func()與call_user_func_array()

還有很多別的方法可以用來規(guī)避遞歸引起的棧溢出問題,比如說Python中可以通過裝飾器和異常來消滅尾調用,讓人有一種別有洞天的感覺。

小結

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

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

    本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多