簡體   English   中英

Parallel.ForEach 比 ForEach 慢

[英]Parallel.ForEach Slower than ForEach

這是代碼:

using (var context = new AventureWorksDataContext())
{
    IEnumerable<Customer> _customerQuery = from c in context.Customers
                                           where c.FirstName.StartsWith("A")
                                           select c;

    var watch = new Stopwatch();
    watch.Start();

    var result = Parallel.ForEach(_customerQuery, c => Console.WriteLine(c.FirstName));

    watch.Stop();
    Debug.WriteLine(watch.ElapsedMilliseconds);

    watch = new Stopwatch();
    watch.Start();

    foreach (var customer in _customerQuery)
    {
        Console.WriteLine(customer.FirstName);
    }

    watch.Stop();
    Debug.WriteLine(watch.ElapsedMilliseconds);
}

問題是, Parallel.ForEach需要大約 400 毫秒,而常規foreach需要大約 40 毫秒。 我到底做錯了什么,為什么這不像我期望的那樣工作?

假設您有一項任務要執行。 假設您是一名數學老師,您有 20 篇論文要評分。 給一篇論文評分需要兩分鍾,所以大約需要四十分鍾。

現在讓我們假設您決定聘請一些助理來幫助您對論文進行評分。 您需要一個小時才能找到四個助手。 你們每人拿四張紙,八分鍾內完成。 您已經用 40 分鍾的工作換來了 68 分鍾的工作,其中包括尋找助手的額外時間,所以這不是節省。 尋找助手的開銷大於自己做這項工作的成本。

現在假設你有兩萬篇論文要評分,所以你需要大約 40000 分鍾。 現在,如果你花一個小時尋找助手,那就是勝利了。 你們每人拿了 4000 篇論文,總共用了 8060 分鍾而不是 40000 分鍾,節省了將近 5 倍。尋找助手的開銷基本上無關緊要。

並行化不是免費的 與每個線程完成的工作量相比,在不同線程之間拆分工作的成本需要很小。

進一步閱讀:

阿姆達爾定律

給出固定工作負載下任務執行延遲的理論加速,這是資源得到改善的系統可以預期的。

古斯塔夫森定律

給出在固定執行時間執行任務的延遲的理論加速,這是資源得到改善的系統可以預期的。

您應該意識到的第一件事是,並非所有並行性都是有益的。 並行性有一定的開銷,根據並行化的復雜性,這種開銷可能重要也可能不重要。 由於並行函數中的工作非常小,並行必須進行的管理開銷變得很大,從而減慢了整體工作的速度。

為您的可枚舉 VS 創建所有線程的額外開銷很可能是導致速度變慢的原因。 Parallel.ForEach不是全面提升性能的舉措; 需要權衡每個元素要完成的操作是否有可能阻塞。

例如,如果您要發出 Web 請求或其他內容,而不是簡單地寫入控制台,則並行版本可能會更快。 事實上,簡單地寫入控制台是一個非常快的操作,因此創建線程和啟動它們的開銷會變慢。

正如之前的作者所說,有一些與Parallel.ForEach相關的開銷,但這並不是您看不到性能改進的原因。 Console.WriteLine是一種同步操作,因此一次只有一個線程在工作。 嘗試將 body 改為非阻塞的東西,你會看到性能提升(只要 body 的工作量足夠大以超過開銷)。

我喜歡所羅門的回答,並想補充一點,您還有額外的開銷

  1. 分配代表。
  2. 通過他們打電話。

暫無
暫無

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

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