Maximum function nesting level of '100' reached, aborting!--漫談再帰:PHPの末尾再帰とその最適化
5354 ワード
Maximum function nesting level of '100' reached, aborting!
言語によってテール再帰のサポートが異なり、コンパイラの最適化も異なります.私たちは前にC言語の末尾再帰を見ましたが、PHPではどうでしょうか.
PHPは末尾再帰に対して最適化効果がない
まず実験を見てみましょう.
XDebugがインストールされている場合は、次のエラーが発生する可能性があります.
これはXDebugの保護メカニズムで、max_を通じてnesting_レベルオプションを設定します.設定を外すと、プログラムは正常に動作します.
コードが正常に動作しても、パラメータを増やし続ける限り、プログラムは遅かれ早かれエラーを報告します.
どうしてですか.簡単に言えば、再帰的にスタックオーバーフローをもたらします.従来の考え方によれば,スタックへの再帰の影響を除去し,プログラムの効率を向上させるために,テール再帰を用いて試みることができる.
XDebugも同様にエラーを報告し,プログラムの実行時間に明らかな変化はなかった.
テール再帰はphpにおいて最適化効果がないことが実証された.
PHPはどのように再帰を除去します
まず、次のソースコードを見てみましょう.
XDebugでは、アラーム効率の問題はなくなりました.
trampoline()関数に気づいたか?簡単に言えば,高次関数を用いて再帰を除去することである.もっと知りたいcall_user_func_Array、この文章を参照してください:PHP関数補完:call_user_func()とcall_user_func_array()
再帰的なスタックオーバーフローの問題を回避するための他にも多くの方法があります.例えば、Pythonでは装飾器や異常でテールコールを消滅させることができ、穴が開いたような感じがします.
小結
Cにおけるテール再帰最適化はgccコンパイラによって行われる.一般的な線形再帰修正がテール再帰の最大の利点は、再帰呼び出しスタックのオーバーヘッドを低減することである.phpの例から,再帰オーバーヘッドがプログラムに及ぼす影響が明らかになった.しかし、すべての言語が末尾再帰をサポートするわけではありません.末尾再帰をサポートする言語でも、C言語の末尾再帰の最適化など、コンパイル段階で末尾再帰を最適化するのが一般的です.テール再帰を使用してコードを最適化する場合は、この言語のテール再帰のサポートを理解する必要があります.
PHPでは、コードの可読性が向上しない限り、再帰を使用する必要はありません.やむを得ない場合は、Tail CallやTrampolineなどの技術を使用して、潜在的なスタックオーバーフローの問題を回避することを考慮したほうがいい.
言語によってテール再帰のサポートが異なり、コンパイラの最適化も異なります.私たちは前にC言語の末尾再帰を見ましたが、PHPではどうでしょうか.
PHPは末尾再帰に対して最適化効果がない
まず実験を見てみましょう.
01
02
function
factorial(
$n
)
03
{
04
if
(
$n
== 0) {
05
return
1;
06
}
07
return
factorial(
$n
-1) *
$n
;
08
}
09
10
var_dump(factorial(100));
11
?>
XDebugがインストールされている場合は、次のエラーが発生する可能性があります.
1
Fatal error: Maximum
function
nesting level of
'100'
reached, aborting!
これはXDebugの保護メカニズムで、max_を通じてnesting_レベルオプションを設定します.設定を外すと、プログラムは正常に動作します.
コードが正常に動作しても、パラメータを増やし続ける限り、プログラムは遅かれ早かれエラーを報告します.
1
Fatal error: Allowed memory size of … bytes exhausted
どうしてですか.簡単に言えば、再帰的にスタックオーバーフローをもたらします.従来の考え方によれば,スタックへの再帰の影響を除去し,プログラムの効率を向上させるために,テール再帰を用いて試みることができる.
01
02
function
factorial(
$n
,
$acc
)
03
{
04
if
(
$n
== 0) {
05
return
$acc
;
06
}
07
return
factorial(
$n
-1,
$acc
*
$n
);
08
}
09
10
11
var_dump(factorial(100, 1));
12
?>
XDebugも同様にエラーを報告し,プログラムの実行時間に明らかな変化はなかった.
1
Fatal error: Maximum
function
nesting level of
'100'
reached, aborting!
テール再帰はphpにおいて最適化効果がないことが実証された.
PHPはどのように再帰を除去します
まず、次のソースコードを見てみましょう.
01
02
function
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
12
function
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
22
var_dump(trampoline(
'factorial'
,
array
(100)));
23
24
?>
XDebugでは、アラーム効率の問題はなくなりました.
trampoline()関数に気づいたか?簡単に言えば,高次関数を用いて再帰を除去することである.もっと知りたいcall_user_func_Array、この文章を参照してください:PHP関数補完:call_user_func()とcall_user_func_array()
再帰的なスタックオーバーフローの問題を回避するための他にも多くの方法があります.例えば、Pythonでは装飾器や異常でテールコールを消滅させることができ、穴が開いたような感じがします.
小結
Cにおけるテール再帰最適化はgccコンパイラによって行われる.一般的な線形再帰修正がテール再帰の最大の利点は、再帰呼び出しスタックのオーバーヘッドを低減することである.phpの例から,再帰オーバーヘッドがプログラムに及ぼす影響が明らかになった.しかし、すべての言語が末尾再帰をサポートするわけではありません.末尾再帰をサポートする言語でも、C言語の末尾再帰の最適化など、コンパイル段階で末尾再帰を最適化するのが一般的です.テール再帰を使用してコードを最適化する場合は、この言語のテール再帰のサポートを理解する必要があります.
PHPでは、コードの可読性が向上しない限り、再帰を使用する必要はありません.やむを得ない場合は、Tail CallやTrampolineなどの技術を使用して、潜在的なスタックオーバーフローの問題を回避することを考慮したほうがいい.