c# – 奇怪的表現行為
所以我有這2個方法,假設將1000個長整數的整數乘以2.
第一種方法:
[MethodImpl(MethodImplOptions.NoOptimization)] Power(int[] arr) { for (int i = 0; i < arr.Length; i++) { arr[i] = arr[i] + arr[i]; } }
第二種方法:
[MethodImpl(MethodImplOptions.NoOptimization)] PowerNoLoop(int[] arr) { int i = 0; arr[i] = arr[i] + arr[i]; i++; arr[i] = arr[i] + arr[i]; i++; arr[i] = arr[i] + arr[i]; i++; ............1000 Times........ arr[i] = arr[i] + arr[i]; }
請注意,我將此程式碼僅用於效能研究,這就是為什麼它看起來很噁心.
令人吃驚的結果是,Power已經比PowerNoLoop快了近50%,即使我檢查了它們的反編譯的IL源,並且For迴圈的內容與PowerNoLoop中的每一行完全相同.
怎麼會這樣?
從我的機器的一個樣品測量,執行測試10次,PowerNoLoop是第一:
00:00:00.0277138 00:00:00.0001553 00:00:00.0000142 00:00:00.0000057 00:00:00.0000106 00:00:00.0000053 00:00:00.0000084 00:00:00.0000053 00:00:00.0000080 00:00:00.0000053 00:00:00.0000075 00:00:00.0000053 00:00:00.0000080 00:00:00.0000057 00:00:00.0000080 00:00:00.0000053 00:00:00.0000080 00:00:00.0000053 00:00:00.0000075 00:00:00.0000053
是的,慢50%左右值得注意的是,首次通過測試時的抖動開銷,顯然它會燃燒更多的核心,試圖得到這個巨大的方法編譯.請記住,當您不禁用優化器時,測量值會大不相同,所以無迴圈版本的速度會慢一些〜800%.
首先總是尋找一個解釋是生成的機器程式碼,你可以看到它與Debug> Windows>拆卸.主要的麻煩是PowerNoLoop()方法的序幕.在x86程式碼中看起來像這樣:
067E0048pushebp; setup stack frame 067E0049movebp,esp 067E004Bpushedi; preserve registers 067E004Cpushesi 067E004Dsubesp,0FA8h; stack frame size = 4008 bytes 067E0053movesi,ecx 067E0055leaedi,[ebp-0ACCh]; temp2 variables 067E005Bmovecx,2B1h; initialize 2756 bytes 067E0060xoreax,eax; set them to 0 067E0062rep stosdword ptr es:[edi]
注意非常大的堆疊大小,4008位元組.對於只有一個區域性變數的方法來說太多了,它只需要8個位元組.額外的4000個是臨時變數,我把它命名為temp2.它們由程式碼指令初始化為0,這需要一段時間.我不能解釋2756.
個人補充是非優化程式碼中非常漂亮的事情.我將為您提供機器程式碼轉儲,並將其寫入等效的C#程式碼:
if (i >= arr.Length) goto throwOutOfBoundsException var temp1 = arr[i]; if (i >= arr.Length) goto throwOutOfBoundsException var temp2 = temp1 + arr[i]; if (i >= arr.Length) goto throwOutOfBoundsException arr[i] = temp2
一遍又一遍地重複,總共一千次. temp2變數是麻煩製造者,每個單獨的語句有一個.因此,為堆疊幀大小新增4000位元組.如果有人猜到2756,那麼我很樂意在評論中聽到.
在方法開始執行之前,必須將它們全部設定為0,大概是什麼導致50%的減速.也可能有一些指令提取和解碼開銷,它不能從測量中輕鬆隔離.
值得注意的是,當您刪除[MethodImpl]屬性並允許優化器執行其作業時,它們不會被消除.實際上,該方法根本沒有優化,因為它不想解決這麼大的程式碼塊.
總結你應該畫的是永遠保持抖動優化器為你展開迴圈.它知道得更好
程式碼日誌版權宣告:
翻譯自:http://stackoverflow.com/questions/32071087/weird-performance-behavior