2008-09-28 65 views
5

由於我使用的for循環的大的多暗淡陣列,在for循環機制的任何節約本身就是有意義的。for循環機制效率的技巧

因此,我在尋找如何降低這種開銷的任何提示。

例如:使用uint而不是int和!= 0作爲停止而不是> 0允許CPU做更少的工作(聽過一次,不確定它總是真的)

+0

看到@monoxide答案。這不應該被標記爲不可知的語言,如果人們知道他們正在優化哪種語言/編譯器,我想你會得到更好的答案。 – 2008-09-28 09:01:37

+0

同意,優化具體的語言和方式,你那句似乎這個問題你是到靶向特定的平臺,以及(運次不同的CPU而異) – Oskar 2008-09-28 10:15:56

+0

標籤的需求,澄清 – Sklivvz 2008-09-28 10:59:46

回答

4

首先,不要出汗的小東西。像倒計時和倒計時這樣的細節通常在運行時間中完全不相關。人類在識別需要加速的代碼領域是非常糟糕的。使用分析器。很少或根本不關注沒有重複的循環的任何部分,除非分析器另有說明。請記住,內部循環中寫入的內容不一定在內部循環中執行,因爲現代編譯器在避免不必要的重複方面非常聰明。

這就是說,要對現代CPU上的循環展開非常謹慎。它們越緊密,它們越適合緩存。在去年工作的高性能應用程序中,我通過使用循環而不是直線代碼來顯着提高性能,並儘可能地收緊它們。 (是的,我進行了分析;所涉及的功能佔用了運行時間的80%。我還基準次以上典型的輸入,所以我知道的變化幫助。)

而且,在開發有利於高效的代碼習慣,沒有壞處。在C++中,你應該習慣使用前增量(++ i)而不是後增(i ++)來增加循環變量。它通常沒有關係,但可以產生顯着差異,它不會使代碼更少可讀或可寫,並且不會受到傷害。

12

一個重要的建議:將盡可能多的計算外環儘可能。並非所有的編譯器都可以自動完成。對於eample,而不是:

for row = 0 to 999 
    for col = 0 to 999 
     cell[row*1000+col] = row * 7 + col 

使用:

for row = 0 to 999 
    x = row * 1000 
    y = row * 7 
    for col = 0 to 999 
     cell[x+col] = y + col 
+0

是的,這與我的建議共鳴:請內循環快。一個例子是Quicksort。 – 2010-06-30 13:55:20

1

當你的循環將有O(N^d)的複雜性(d =尺寸),真正重要的是你把進入死循環,而不是循環本身。在循環內優化幾個循環,從循環內部數百萬循環的低效率算法開始,就是蛇油。

+0

我從來沒有發現O符號有用,除非比較兩個執行相同事情的算法。說Bubble排序是O(n^2)而Quicksort是O(n lg n)是有道理的。對我來說,說一些東西是O(n^2),沒有類似的東西來比較它是沒有道理的。 – 2008-09-28 10:52:05

+0

要學究:基本實現快速排序的爲O的平均情況複雜度(N log n)的,但仍然爲O的最壞情況複雜度(N^2)。 – 2008-09-28 13:25:41

5

循環展開可以是單向的。那就是:

for (i=0; i<N; i++) { 
    a[i]=...; 
} 

轉變爲:

for (i=0; i<N; i+=4) { 
    a[i]=...; 
    a[i+1]=...; 
    a[i+2]=...; 
    a[i+3]=...; 
} 

您將需要進行特殊處理當N不是4在上面的例子多。

6

您是否測量了開銷?你知道花了多少時間處理for循環,花費多少時間來執行應用程序代碼?你的目標是什麼?

4

這不是一個語言無關的問題,這在很大程度上取決於不僅語言,而且編譯器。大多數編譯器,我相信會編這兩種等價的:

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

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

在大多數語言/編譯器,for循環是爲以後的while循環只是語法糖。 Foreach又是另一個問題,並且高度依賴於語言/編譯器如何實現,但通常是for/while循環效率較低。還有多少,語言和編譯器依賴。

您最好的選擇可能是就一個主題運行一些基準測試與幾個不同的變化,看看是什麼在上面出來。

編輯:爲此,該suggestions here可能會爲您節省更多的時間,而不是擔心循環本身。

3

我同意@Greg。你需要做的第一件事是放置一些基準。除非您證明您的處理時間花費在哪裏,否則將毫無意義地優化任何內容。 「過早優化是萬惡之源」!

9

試着讓你的循環在內存中連續,這將優化緩存使用率。也就是說,不這樣做:

for (int i = 0; i < m; i++) 
    for (j = 0; j < n; j++) 
     s += arr[j][i]; 
  • 如果處理圖像,轉換兩個循環到一個循環上的像素用單一指標。
  • 不要讓循環運行零次,因爲管道已經過優化,假設循環將繼續而不是結束。
4

順便說一句,除非你需要後增量,你應該總是使用前增量操作符。這只是一個小小的區別,但它更有效率。

內部此的區別是:

  • 後增量

    i++;

    相同:

    int postincrement(int &i)
    {
    int itmp = i;
    i = i + 1;
    return itmp;
    }

  • 預公司種類調和

    ++i;

    是一樣的:

    int preincrement(int &i)
    {
    i = i + 1;
    return i;
    }

0

我想大多數編譯器可能會做這個,無論如何,降壓零應該更有效,因爲一檢查處理器的零速度非常快。不過,任何值得它的權重的編譯器都會在大多數循環中執行此操作。你需要知道編譯器在做什麼。

0

沒有足夠的信息來準確回答你的問題。你在循環中做什麼?一次迭代中的計算是否取決於先前迭代中計算的值。如果不是的話,假設你至少有一個雙核處理器,那麼只需簡單地使用2個線程就可以將時間縮短一半。

另一件事看是你如何訪問您的數據,如果你正在做大型陣列處理,以確保您訪問數據依次的,因爲它是存儲在內存中,避免沖洗的L1/L2緩存在每次迭代中(在較小的L1緩存中可以看到這種差異,這種差異可能很大)。

再一次,我會先看看循環內部是什麼,大部分增益(> 99%)將會在哪裏,而不是外部循環管道。但是,如果你的循環代碼是I/O綁定的,那麼在優化上花費的任何時間都是浪費的。

1

順便說一句,是不是很好用short,而不是int在循環,如果Int16的能力是保證足夠?