2016-03-04 81 views
1

我有這個巨大的json文件整齊地以字符「[\ r \ n」開始並以「]」結尾。我有這樣一段代碼:首先在IEnumerable中跳過,然後繼續執行

foreach (var line in File.ReadLines(@"d:\wikipedia\wikipedia.json").Skip(1)) 
{ 
    if (line[0] == ']') break; 
    // Do stuff 
} 

我想知道,什麼是最好的性能,明智的,什麼樣的機器代碼將是最優化的問候多少個時鐘週期和內存,如果我要被消耗將上面的代碼與我用「continue」代替「break」的代碼進行比較,或者將這兩段代碼編譯爲相同的MSIL和機器代碼?如果你知道答案,請解釋你是如何得出你的結論的?我真的很想知道。

編輯:在關閉這個無意義的代碼之前,請考慮這段代碼等同於上面的代碼,並且認爲當代碼路徑是平坦的並且不會以很多方式分叉時,c#編譯器會進行優化,以下示例爲CPU生成相同的工作量?

IEnumerable<char> text = new[] {'[', 'a', 'b', 'c', ']'}; 
foreach (var c in text.Skip(1)) 
{ 
    if (c == ']') break; 
    // Do stuff 
} 
foreach (var c in text.Skip(1)) 
{ 
    if (c == ']') continue; 
    // Do stuff 
} 
foreach (var c in text.Skip(1)) 
{ 
    if (c != ']') 
    { 
     // Do stuff      
    } 
} 
foreach (var c in text.Skip(1)) 
{ 
    if (c != ']') 
    { 
     // Do stuff      
    } 
} 
foreach (var c in text.Skip(1)) 
{ 
    if (c != ']') 
    { 
     // Do stuff      
    } 
    else 
    { 
     break; 
    } 
} 

EDIT2:這裏是把它的另一種方式:什麼是跳過一個IEnumerable的第一個和最後一個項目的最漂亮的方式,同時還推遲執行,直到//做的東西?

+4

最好的選擇是使用JSON解析器而不是做這個自我。 – HimBromBeere

+0

你問如何解析JSON?還是你問如何基準代碼? – mason

+0

我無法做到這一點,該文件太大,但我使用牛頓軟件來解析各條線。 – Marcus

回答

3

問:不同的MSIL打破或繼續循環?

是的,這是因爲它的工作原理是這樣的:

foreach (var item in foo) 
{ 
    // more code... 

    if (...) { continue; } // jump to #1 
    if (...) { break; } // jump to #2 

    // more code... 

    // #1 -- just before the '}' 
} 

// #2 -- after the exit of the loop. 

問:什麼會給你最性能?

分支是編譯器的分支。如果您有gotocontinuebreak,它最終將被編譯爲分支(操作碼br),這將進行分析。換句話說:它沒有什麼區別。

什麼確實有所作爲在代碼中具有可預測的數據和代碼流模式。分支會破壞代碼流,所以如果你想要性能,你應該避免不規則的分支。

換句話說,寧願:

for (int i=0; i<10 && someCondition; ++i) 

到:

for (int i=0; i<10; ++i) 
{ 
    // some code 
    if (someCondition) { ... } 
    // some code 
} 

一如既往與性能,最好的事情就是運行基準測試。沒有替代品。

問:什麼會給你最多的表現? (#2)

你正在做很多與IEnumerable的。如果您需要原始性能並有選擇權,最好使用arraystring。在原始性能方面沒有更好的選擇來順序訪問元素

如果數組不是一個選項(例如因爲它不匹配訪問模式),最好使用最適合訪問模式的數據結構。瞭解哈希表(Dictionary),紅黑樹(SortedDictionary)以及List如何工作的特性。關於的知識如何真正起作用是您需要的東西。如果不確定,請再次測試,測試和測試。

問:什麼會給你最多的表現? (#3)

我也會嘗試JSON庫,如果你的意圖是解析。這些人可能已經爲你發明了輪子 - 如果沒有,它會給你一個「擊敗」的基線。

問:[...]什麼是跳過第一個和最後一個項目的最漂亮的方式[...]

如果底層的數據結構是stringListarray,我會簡單地這樣做:

for (int i=1; i<str.Length-1; ++i) 
{ ... } 

坦率地說,其他數據結構在這裏真的沒有意義。這就是說,人出頭喜歡把LINQ的代碼無處不在,所以......

使用枚舉

您可以輕鬆地返回所有,但第一個和最後一個元素的方法。在我的書中,枚舉器總是通過諸如foreach之類的代碼進行訪問,以確保IDisposable被正確調用。

public static IEnumerable<T> GetAllButFirstAndLast<T>(IEnumerable<T> myEnum) 
{ 
    T jtem = default(T); 
    bool first = true; 
    foreach (T item in myEnum.Skip(1)) 
    { 
     if (first) { first = false; } else { yield return jtem; } 
     jtem = item; 
    } 
} 

請注意,這與「從代碼中獲得最佳性能」無關。一看IL就會告訴你所有你需要知道的事情。

+0

對我來說,主要的挑戰是:有什麼有所作爲的是在代碼中具有數據和代碼流的可預測模式。分支會破壞代碼流,所以如果你想要性能,你應該避免不規則的分支。 – Marcus

+0

但是,假設你必須在循環中多次執行某些操作,並且每次迭代都需要檢查一個條件,例如「計數小於最大大小」,那麼while循環的性能將優於if子句嗎?我正在迭代67GB的json,數百萬條記錄。我想知道我不會不必要地分支。 – Marcus

+1

@Marcus分支較少(通常是最短代碼)的可預測模式通常更好。我在這裏寫了一堆關於你的編譯器如何處理分支的東西:http://stackoverflow.com/questions/324831/breaking-out-of-a-nested-loop/35755622#35755622。請注意,while循環也是一個分支,就像從IL的角度來看if一樣。 – atlaste