乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      探索c#之尾遞歸編譯器優(yōu)化

       weijianian 2016-08-07


      作者:蘑菇先生

      網(wǎng)址:http://www.cnblogs.com/mushroom/p/4311952.html


      遞歸運(yùn)用


      一個(gè)函數(shù)直接或間接的調(diào)用自身,這個(gè)函數(shù)即可叫做遞歸函數(shù)。


      • 遞歸主要功能是把問題轉(zhuǎn)換成較小規(guī)模的子問題,以子問題的解去逐漸逼近最終結(jié)果。

      • 遞歸最重要的是邊界條件,這個(gè)邊界是整個(gè)遞歸的終止條件。


      static int RecFact(int x)

      {

      if (x == 0)

      return 1;

      return x * RecFact(x - 1);

      }

      RecFact(10);


      上面是個(gè)經(jīng)典階乘函數(shù)的實(shí)現(xiàn)。這里分2步:


      • 轉(zhuǎn)換,把10的階乘轉(zhuǎn)化成10*9!,10(9*8!)....每次轉(zhuǎn)換規(guī)模就變的更小。

      • 逼近,轉(zhuǎn)換到最小規(guī)模時(shí)0!,求解1。開始逆向合并逐漸逼近到10,得出解。


      這里的x==0就是我們的邊界條件(即終止條件),也有的依賴外部變量為邊界。


      如果一個(gè)遞歸函數(shù)沒有邊界,也就無法停止(無限循環(huán)至內(nèi)存溢出),當(dāng)然這樣也沒什么意義。


      RecFact調(diào)用堆棧:




      常見使用場景:


      • 階乘/斐波那契數(shù)列/漢諾塔

      • 遍歷硬盤文件

      • InnerExceptions異常撲捉(exception.InnerException==null)


      尾遞歸優(yōu)化


      當(dāng)邊界不明確的時(shí)候,遞歸就很容易出現(xiàn)溢出問題。


      在階乘過程中,堆棧需要保存每次(RecFact)調(diào)用的返回地址及當(dāng)時(shí)所有的局部變量狀態(tài),期間堆棧空間是無法釋放的(即容易出現(xiàn)溢出)。


      為了優(yōu)化堆棧占用問題,從而提出尾遞歸優(yōu)化的辦法。


      static void TailRecursion(int x)

      {

      Console.WriteLine(x);

      if (x == 10)

      return;

      TailRecursion(x + 1);

      }

      TailRecursion(0);


      使用尾遞歸堆棧可以不用保存上次的函數(shù)返回地址/各種狀態(tài)值,而方法遺留在堆棧上的數(shù)據(jù)完全可以釋放掉,這是尾遞歸優(yōu)化的核心思想。


      由于尾遞歸期間,堆棧是可以釋放/再利用的,也就解決遞歸過深而引起的溢出問題,這也是尾遞歸的優(yōu)勢所在。


      編譯器優(yōu)化


      尾遞歸優(yōu)化,看起來是蠻美好的,但在net中卻有點(diǎn)亂糟糟的感覺。


      • Net在C#語言中是JIT編譯成匯編時(shí)進(jìn)行優(yōu)化的。

      • Net在IL上,有個(gè)特殊指令tail去實(shí)現(xiàn)尾遞歸優(yōu)化的(F#中)。


      我們執(zhí)行 TailRecursion(0)(x==1000000) 得出如下結(jié)論:


      C#/64位/Release是有JIT編譯器進(jìn)行尾遞歸優(yōu)化的(非C#編譯器優(yōu)化)。




      C#/32位或C#/Debug模式中JIT是不進(jìn)行優(yōu)化的。




      F#在優(yōu)化尾遞歸也分2種情況:


      1、 簡單的尾遞歸優(yōu)化成while循環(huán),如下:


      let rec TailRecursion(x) =

      if (x = 1000) then true

      else TailRecursion(x + 1)


      (方便演示C#呈現(xiàn))編譯器優(yōu)化成:


      public static bool TailRecursion(int x)

      {

      while (x != 0x3e8)

      {

      x++;

      }

      return true;

      }


      2、 復(fù)雜的尾遞歸,F(xiàn)#編譯器會生成IL指令Tail進(jìn)行優(yōu)化,如下:


      let TailRecursion2 a cont = cont (a + 1)


      優(yōu)化成:




      如何定義復(fù)雜的尾遞歸呢?通常是后繼傳遞模式(CPS)。


      F#中在debug模式下,需要在編譯時(shí)配置:




      總結(jié)


      在C#語言(過程式/面向?qū)ο缶幊趟枷?中,優(yōu)先考慮的是循環(huán),而不是遞歸/尾遞歸。 但在函數(shù)式編程思想當(dāng)中,遞歸/尾遞歸使用則是主流用法,就像在C#使用循環(huán)一樣。


      參考資料


      http:///blog/62412678347


      http:///questions/15864670/generate-tail-call-opcode



      DotNet

      微信號:iDotNet

      打造東半球最好的 .Net 微信號

      --------------------------------------

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

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多