2010-02-11 262 views
10

是更好,如果我這樣做:如果循環內部或外部的語句?

foreach my $item (@array) { 
    if ($bool) { 
    .. code .. 
    } 
    else { 
    .. code .. 
    } 
} 

if ($bool) { 
    foreach my $item (@array) { 
    } 
} 
else { 
    foreach my $item (@array) { 
    } 
} 
+4

$ bool是否被循環中的任何內容所改變? – 2010-02-11 04:58:35

+0

$ bool是一個不變的靜態變量。 – Timmy 2010-02-11 05:24:56

+1

不要爲'foreach'循環的每次迭代執行'if else'。第二個例子肯定是要走的路。 – JohnB 2010-11-04 23:23:41

回答

18

我會把premature optimization放在一旁。

「過早的優化是萬惡之根」 - 高德納

你應該去維護第一位的。以更有意義的方式對它們進行分組,將代碼的邏輯結構考慮在內(例如將相關的語句組合在一起)。

如果您以後確定性能問題,請嘗試使用類似探查器的測量來查看瓶頸位置。機會是,它不在那裏。從代碼完成2:

巴里貝姆報告說, 20%的程序的程序佔用80%的 它的執行時間。在他的 經典論文「關於 Fortran程序的實證研究」中,Donald Knuth發現 ,其中不到百分之四的 程序通常佔其運行時間的50%多於 。

因爲我們大多數人在猜測代碼的慢部分在哪裏真的很糟糕,所以我們不應該試圖猜測在哪裏進行優化。隨時進行優化的程序員也花費大約96%的時間優化不需要優化的代碼。考慮到另一件事是,代碼調整(如本例)認爲性能可讀性和可維護性之間的權衡: 初始開發期間

着眼於優化從 有損其他實現計劃目標。 開發人員將自己沉浸在 算法分析和奧術辯論 那最後不會爲用戶貢獻太多 值。如 正確性,信息隱藏和 可讀性的擔心成爲次要目標,即使性能更容易 改善晚於其他 關注的是。事後性能 工作通常會影響少於五個程序代碼的百分之五十 。請問 寧願退回,並在百分之五的代碼或 可讀性工作上做性能工作 ?

我不是說不優化,但優化最終唯一的代碼,當你有大局和工具的奢侈品你指出正確的方向。

EXTRA:要回答的表演本身的問題,但:

這[ 「外提」 代碼]有利於節省時間約20%:

Language  Straight Time Code-Tuned Time Time Savings 
C++    2.81    2.27    19%  
Java   3.97    3.12    21% 
Visual Basic 2.78    2.77    <1% 
Python   8.14    5.87    28% 

不同於這種情況的一個危險是兩個迴路必須保持平行。 [...]您必須記住在兩個地方更改代碼,這對您而言是一個煩惱,對於需要使用代碼的任何其他人而言,這是一個令人頭痛的問題。

該示例還說明了代碼優化中的關鍵挑戰:任何特定代碼優化的效果都不可預測。代碼調優在 四種語言中的三種中產生了重大改進,但在Visual Basic中卻沒有這種改進。要在此特定版本的Visual Basic中執行此特定的 優化,將產生較少的可維護代碼,而不會在性能方面帶來任何抵消性增益。一般的教訓是,您必須測量每個特定優化的效果以確保其效果 - 沒有 例外。

檢查this other關於SO的問題。和Code Complete第一版中的this

+7

我不知道在編寫代碼時考慮性能影響總是過早的優化。我同意在這種情況下它可能可以忽略不計,但我並不總是同意「不成熟的優化」總括聲明。 – 2010-02-11 04:33:23

+4

@Andy:好的,就選擇正確的算法等而言,是的,你必須意識到選擇哪一個,所以你最終不會認真對待你的程序。但是一般來說,在儘可能以最清晰的方式編寫程序(可能做重構以消除任何過早的優化)後,您的分析器將會很好地告訴您需要修復的問題。 – 2010-02-11 04:48:56

+4

思維很好。對性能的思考是很好的。但是如果你的編譯器不會爲語義相同的結構生成相同的代碼,那麼現在是時候修復你的編譯器了。不要爲了解決語言實現錯誤而微觀優化應用程序,這是錯誤的抽象層次。 – jrockway 2010-02-11 06:48:54

3

我建議你既時間,看看自己,但我不希望的差異是巨大的。

5

如果你正在爲速度進行優化,第二個(在if分支內的foreach循環)應該更快,因爲你不會在每個循環迭代中進行測試。

+0

你應該編寫程序併爲自己測試。 :-P我所做的時間測試表明差異可以忽略不計。 – 2010-02-11 04:26:33

+0

@Chris Jester-Young:好的,我做到了。我的代碼初始化了一個100萬個元素的數組,然後循環遍歷它將元素寫入文件。第二種方法(在if內部循環)始終快速且在.3秒至1.6秒之間變化,平均爲0.7秒(每次運行約17秒),平均提高約4%。授予,不大,但是否重要取決於具體情況。 – GreenMatt 2010-02-14 04:32:28

+0

在我的書中,17秒的差距可以忽略不計,但是就像你說的,我認爲這取決於上下文。 :-) – 2010-02-14 05:17:03

7

第二個比較快,因爲比較次數少得多。 - 比較是在循環之外而不是內部。

由於比較變量是一個循環不變量,如果它不是更清晰的編碼,我會感到驚訝。

實際轉速差(掛鐘時間)取決於陣列

2

簡單評估布爾變量,你在這裏做的大小,這些是大致相當於。但是,如果將變量替換爲花費很長時間評估的複雜表達式,則第二個示例會更好,因爲它只會被評估一次。

+2

或者您可以將$ bool設置爲複雜表達式的值:) – ysth 2010-02-11 04:49:43

+0

確實如此。那是很自然的事情。 – 2010-02-11 05:21:03

4

每個人似乎都停留在性能問題上。

無需重複代碼幾乎總是更好。也就是說,多次輸入同一個東西對你來說應該是很痛苦的。既然你沒有對每個代碼都說過什麼,我會假設你想在每種情況下做不同的事情。我的偏好是將迭代的細節與特定的處理分開。

my $sub_ref = $bool ? make_true_function() : make_false_function(); 

foreach my $element (@array) { 
     $sub_ref->($element); 
     } 

sub make_true_function { sub { ... } } 
sub make_false_function { sub { ... } } 

這可能會在性能上失去一點點,但由於代碼不那麼糾結,所以看起來要容易得多。 foreach不關心任何關於分支或你如何做出決定。當你想擁有更多的分支時,這個效果很好。只要$sub_ref中出現正確的東西,您就不會更改迭代代碼。