簡體   English   中英

for()和while()之間是否有任何性能差異?

[英]Is there any performance difference between for() and while()?

或者它是關於語義的嗎?

簡答:不,他們完全一樣。

猜測它理論上可能依賴於編譯器; 一個真正破碎的人可能會做一些略有不同的事情,但我會感到驚訝。

只是為了好玩,這里有兩個變種,使用Ubuntu附帶的x86 gcc版本4.3.3編譯為完全相同的匯編代碼。 您可以使用linux上的objdump檢查最終二進制文件上生成的程序集。

int main()
{
#if 1
    int i = 10;
    do { printf("%d\n", i); } while(--i);
#else
    int i = 10;
    for (; i; --i) printf("%d\n", i);
#endif
}

編輯:這是一個“橘子與橘子”,而循環示例也編譯成同樣的東西:

while(i) { printf("%d\n", i); --i; }

如果for和while循環執行相同的操作,編譯器生成的機器代碼應該(幾乎)相同。

比如幾年前我做的一些測試,

for (int i = 0; i < 10; i++)
{
...
}

int i = 0;
do
{
  ...
  i++;
}
while (i < 10);

將生成完全相同的代碼,或者(和Neil在評論中指出)使用一個額外的jmp,這將不會在性能上產生足夠大的差異而擔心。

沒有語義差異,不需要任何編譯差異。 但這取決於編譯器。 所以我嘗試使用g ++ 4.3.2,CC 5.5和xlc6。

g ++,CC是相同的,xlc不是

xlc的差異在於初始循環條目。

extern int doit( int );
void loop1( ) {
  for ( int ii = 0; ii < 10; ii++ ) {
    doit( ii );
  }
}

void loop2() {
  int ii = 0; 
  while ( ii < 10 ) {
    doit( ii );
    ii++;
  }
}

XLC輸出

.loop2:                                 # 0x00000000 (H.10.NO_SYMBOL)
    mfspr   r0,LR
    stu     SP,-80(SP)
    st      r0,88(SP)
    cal     r3,0(r0)
    st      r3,64(SP)
    l       r3,64(SP)  ### DIFFERENCE ###
    cmpi    0,r3,10
    bc      BO_IF_NOT,CR0_LT,__L40
...
enter code here
.loop1:                                 # 0x0000006c (H.10.NO_SYMBOL+0x6c)
    mfspr   r0,LR
    stu     SP,-80(SP)
    st      r0,88(SP)
    cal     r3,0(r0)
    cmpi    0,r3,10    ### DIFFERENCE ###
    st      r3,64(SP)
    bc      BO_IF_NOT,CR0_LT,__La8
...

while循環測試中變量的范圍比for循環標題中聲明的變量范圍更寬。

因此,如果存在性能影響作為保持變量更長時間活動的副作用,那么在while和for循環之間進行選擇會產生性能影響(並且不會在{}中包含while,以縮小其范圍。變量)。

一個示例可能是並發集合,它計算引用它的迭代器的數量,如果存在多個迭代器,它會應用鎖定以防止並發修改,但如果只有一個迭代器引用它,優化就會使鎖定失敗。 如果你在一個函數中有兩個for循環,在同一個容器上使用不同名稱的迭代器,那么將采用快速路徑,但是使用兩個while循環時將采用慢速路徑。 同樣,如果對象很大(更多緩存流量)或使用系統資源,可能會對性能產生影響。 但我想不出一個我見過的真正的例子,它會產生什么影響。

使用循環展開優化的編譯器可能只在for-loop情況下這樣做。

兩者都是等價的。 這是一個語義問題。

唯一的區別可能在於做... while結構,在那里你推遲條件的評價,直到身體 ,從而可節省1分的評價。

i = 1; do { ... i--; } while( i > 0 ); 

而不是

for(  i = 1; i > 0; --i )
{ ....
}  

我寫編譯器。 我們將所有“結構化”控制流( ifwhileforswitchdo ... while )編譯成條件和無條件分支。 然后我們分析控制流圖。 由於C編譯器無論如何都必須處理一般goto ,因此最簡單的方法是將所有內容都減少為分支和條件分支指令,然后一定要很好地處理這種情況。 (AC編譯器不僅要在手寫代碼上做得很好,還要在自動生成的代碼上做得很好,這些代碼可能有很多很多的goto語句。)

不。如果他們正在做相同的事情,他們將編譯成相同的代碼 - 正如你所說,它是關於語義。 選擇最能代表您要表達的內容的那個。

理想情況下它應該是相同的,但最終它取決於您的編譯器/解釋器。 當然,您必須測量或檢查生成的匯編代碼。

證明可能存在差異:這些線使用cc65生成不同的匯編代碼。

for (; i < 1000; ++i);   
while (i < 1000) ++i;

Atmel ATMega雖然()比()更快。 為什么在AVR035中解釋了這一點:AVR的高效C編碼。

PS原始平台沒有提到問題。

繼續forwhile中表現不同:in for ,它改變了計數器, 而while通常不會

添加另一個答案:根據我的經驗,優化軟件就像是一個被人剃掉的大而濃密的胡須。

  • 首先,你用剪刀將它用大塊切掉(從調用樹上修剪整個肢體)。
  • 然后用電動剪刀(調整算法)縮短它。
  • 最后你用剃須刀剃掉它以擺脫最后一點(低級優化)。

最后一個是for()while()之間的差異,但可能不會產生影響。

PS我認識的程序員(他們都非常好,我懷疑是一個有代表性的樣本)基本上從另一個方向去做。

就性能而言,它們是相同的。 我傾向於使用while等待狀態改變(例如,等待一個緩沖器被填充),並且當for處理多個離散的對象(諸如一個集合中的每個項目去)時。

在某些情況下存在差異。

如果您處於這種差異很重要的位置,您需要選擇更好的算法或開始使用匯編語言進行編碼。 相信我,在匯編中編碼比修復編譯器版本更可取。

while()快/慢for() 讓我們回顧一下有關優化的一些事情:

  • 編譯器編寫器通過減少調用跳轉,比較,增量以及它們生成的其他類型的指令來非常努力地削減周期。

  • 另一方面,調用指令會消耗更多的周期,但是編譯器幾乎無能為力去除它​​們。

  • 作為程序員,我們編寫了很多函數調用,有些是因為我們的意思是,有些因為我們很懶,有些因為編譯器將它們滑入而沒有顯而易見。

  • 大多數時候,這並不重要,因為硬件太快了,而且我們的工作很小,以至於計算機就像一只小獵犬,狼吞虎咽地吃着她的食物並且乞求更多。

  • 然而,有時候,這項工作足夠大,以至於性能成為一個問題。

  • 那我們做什么? 哪里有更大的回報?

    • 讓編譯器在循環中減少幾個周期?
    • 找到非真正需要完成的函數調用?
  • 編譯器不能做后者。 只有我們程序員才能。

  • 我們需要學習或教會如何做到這一點。 它不是自然而然的。 我們先天傾向於做出錯誤的猜測,然后押注於他們。 獲得更好的算法是一個開始,但只是一個開始。 我們的老師需要教這個,如果他們確實知道如何。

  • Profilers是一個開始。 我這樣做

Willie Sutton在被問到為什么要搶銀行時的虛偽引用
因為這就是錢的所在。

如果您想保存周期,請找出它們的位置。

可能只是編碼風格。

  • 如果您知道迭代次數。
  • 而如果你不知道迭代次數。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM