2013-05-06 12 views
0

我想看看下面兩個簡單的遞歸函數將執行以及C#版本一個循環,所以我用ILSPY反編譯他們到C#。反編譯一個簡單的遞歸函數,並得到不必要代碼

let rec findPivot i = 
     if i = 0 then -1 
     else 
      if myArray.[i] > myArray.[i-1] then i - 1 
      else findPivot (i - 1) 

    let rec findTarget value i = 
     if (myArray.[i] > value) then i 
     else findTarget value (i - 1) 

獲取:

internal static int [email protected](int[] myArray, int i) 
{ 
    while (i != 0) 
    { 
     if (myArray[i] > myArray[i - 1]) 
     { 
      return i - 1; 
     } 
     int[] arg_22_0 = myArray; // useless 
     i--; 
     myArray = arg_22_0; // useless 
    } 
    return -1; 
} 

internal static int [email protected](int[] myArray, int value, int i) 
{ 
    while (myArray[i] <= value) 
    { 
     int[] arg_16_0 = myArray; // useless 
     int arg_14_0 = value; // useless 
     i--; 
     value = arg_14_0; // useless 
     myArray = arg_16_0; // useless 
    } 
    return i; 
} 

我很驚訝的是,F#編譯會產生這樣的亂碼。雖然它可能不會影響性能(JIT可能會進一步優化)。當代碼在系統中更加複雜和關鍵時,我仍然擔心性能問題。

關於爲什麼編譯器發出這樣的代碼的任何意見?

+3

你真的看了IL而不是反編譯的代碼--F#編譯器實際上生成了很好的il,所以也許反編譯器轉換回C#生成奇數代碼。 – 2013-05-06 23:28:24

+1

除了John Palmer的觀察,請記住,IL並不是實際運行的 - JIT編譯器可能會在轉換爲機器代碼時優化不需要的操作。我會分析代碼,看看你是否有實際的性能問題,而不是預先擔心它。 – kvb 2013-05-07 01:47:19

+2

+1給kvb的觀點。檢查這個:https://gist.github.com/v2m/5530153 - JIT優化堆棧操作。 – desco 2013-05-07 03:56:35

回答

2

我仔細研究過它,似乎IL被誤解爲一個新的本地聲明。請記住,F#編譯器生成的IL並不總是與C#編譯器相匹配。似乎F#編譯器會重新分配參數,而不管它們是否在循環中發生了變異。注意我們沒有宣佈當地人,所以一切都被推入堆棧。

.method public static 
    int32 findTarget (
     int32 'value', 
     int32 i 
    ) cil managed 
{ 
    .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = (
     01 00 02 00 00 00 01 00 00 00 01 00 00 00 00 00 
    ) 
    // Method begins at RVA 0x2084 
    // Code size 27 (0x1b) 
    .maxstack 8 

    // loop start 
     IL_0000: nop 
     IL_0001: call int32[] Program::get_myArray() 
     IL_0006: ldarg.1 
     IL_0007: ldelem.any [mscorlib]System.Int32 
     IL_000c: ldarg.0 
     IL_000d: ble.s IL_0011 

     IL_000f: ldarg.1 
     IL_0010: ret 

     IL_0011: ldarg.0 
     IL_0012: ldarg.1 
     IL_0013: ldc.i4.1 
     IL_0014: sub 
     IL_0015: starg.s i 
     IL_0017: starg.s 'value' 
     IL_0019: br.s IL_0000 
    // end loop 
} // end of method Program::findTarget