簡體   English   中英

在IEnumerable中跳過第一個和最后一個,推遲執行

[英]Skip first and last in IEnumerable, deferring execution

我把這個巨大的json文件整齊地格式化,從字符“[\\ r \\ n”開頭,以“]結尾”開頭。 我有這段代碼:

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

我想知道,在性能方面最好的是什么,如果我將上面的代碼與我已經替換“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中跳過第一個和最后一個項目的最漂亮的方法是什么,同時仍然推遲執行直到// Do stuff?

問:不同的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 對於元素的順序訪問,原始性能方面沒有更好的選擇。

如果數組不是一個選項(例如,因為它與訪問模式不匹配),最好使用最適合訪問模式的數據結構。 了解哈希表(字典),紅黑樹(SortedDictionary)的特征以及List的工作原理。 關於東西真正起作用的知識就是你需要的東西。 如果不確定,再次進行測試,測試和測試。

問:什么會給你最大的表現? (#3)

如果你打算解析它,我也會嘗試JSON庫。 這些人可能已經為你發明了輪子 - 如果沒有,它會給你一個“擊敗”的基線。

問:[...]跳過第一個和最后一個項目最漂亮的方法是什么[...]

如果底層數據結構是stringListarray ,我只需這樣做:

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

坦率地說,其他數據結構在IMO中並沒有多大意義。 也就是說,人們喜歡將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就會告訴你所有你需要知道的事情。

暫無
暫無

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

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