![](/img/trans.png)
[英]Why is this loop in a then callback faster than in an async function?
[英]Why is recursion faster than a flat for loop for a summation function on JavaScript?
我正在使用一種翻譯成JavaScript的語言。 為了避免一些堆棧溢出,我通過將某些函數轉換為for循環來應用尾調用優化。 令人驚訝的是,轉換並不比遞歸版本快。
http://jsperf.com/sldjf-lajf-lkajf-lkfadsj-f/5
遞歸版:
(function recur(a0,s0){
return a0==0 ? s0 : recur(a0-1, a0+s0)
})(10000,0)
尾部調用優化后:
ret3 = void 0;
a1 = 10000;
s2 = 0;
(function(){
while (!ret3) {
a1 == 0
? ret3 = s2
: (a1_tmp$ = a1 - 1 ,
s2_tmp$ = a1 + s2,
a1 = a1_tmp$,
s2 = s2_tmp$);
}
})();
ret3;
使用Google Closure Compiler進行一些清理之后:
ret3 = 0;
a1 = 1E4;
for(s2 = 0; ret3 == 0;)
0 == a1
? ret3 = s2
: (a1_tmp$ = a1 - 1 ,
s2_tmp$ = a1 + s2,
a1 = a1_tmp$,
s2 = s2_tmp$);
c=ret3;
遞歸版本比“優化”版本更快! 如果遞歸版本必須處理數以千計的上下文更改,那怎么可能呢?
優化比尾部調用優化更多。
例如,我注意到你正在使用兩個臨時變量,只需要:
s2 += a1;
a1--;
僅這一點實際上將操作次數減少了三分之一,從而使性能提高了50%
從長遠來看,在嘗試優化操作本身之前優化正在執行的操作非常重要。
編輯:這是一個更新的jsperf
遞歸版本中的上下文變化並不像您期望的那么多,因為命名函數recur
包含在recur
本身的范圍內/它們共享相同的范圍。 其原因與JavaScript引擎評估范圍的方式有關,並且有很多網站可以解釋這個主題,所以我不會在這里做。 再看看你會注意到recur
也是一個所謂的“純”函數,這基本上意味着只要內部執行運行它就永遠不會離開它自己的范圍(簡單地說:直到它返回一個值)。 這兩個事實使它基本上很快。 我只想在這里提一下,第一個例子是所有三個中唯一的尾部調用優化 - tc優化只能在遞歸函數中完成,這是唯一的遞歸函數。
然而,第二個看第二個例子(沒有雙關語)揭示了“優化器”使你的事情變得更糟,因為它通過將操作分成以前的操作將范圍引入到前一個純函數中
while
循環 這導致性能較差,因為現在引擎必須處理10000個上下文更改。
說實話我不知道為什么第三個例子的性能比遞歸的差,所以它可能與:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.