Parallel.ForEach比ForEach慢

时间:2011-05-17 19:32:28

标签: c# .net parallel.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与常规foreach相比需要大约400毫秒,大约需要40毫秒。我究竟做错了什么,为什么这不能像我期望的那样工作?

5 个答案:

答案 0 :(得分:148)

假设您要执行任务。假设你是一名数学老师,你有二十篇论文要评分。你需要花两分钟来评分一张纸,所以它需要大约四十分钟。

现在让我们假设您决定聘请一些助手来帮助您评分论文。找一个四个助手需要一个小时。你们各自拿了四篇论文,你们都在八分钟内完成了。你已经交易了40分钟的工作,总共68分钟的工作,包括额外的时间来找到助手,所以这不是节省。找到助手的开销大于自己完成工作的成本。

现在假设您有两万篇论文要评分,所以它需要大约40000分钟。现在,如果你花一个小时寻找助手,那就是胜利。你们各自拿了4000篇论文,共计8060分钟而不是40000分钟,节省了近5倍。找到助手的开销基本上是无关紧要的。

并行化不是免费的与每个线程完成的工作量相比,在不同线程之间拆分工作的成本需要很小。

进一步阅读:

https://en.wikipedia.org/wiki/Amdahl%27s_law

https://en.wikipedia.org/wiki/Gustafson%27s_law

答案 1 :(得分:9)

你应该意识到的第一件事是并非所有的并行都是有益的。并行性存在大量开销,并且这种开销可能会或可能不会很大,这取决于并行化的复杂性。由于并行功能中的工作量非常小,因此并行操作所需的管理开销变得很大,从而减慢了整体工作。

答案 2 :(得分:9)

为可枚举的VS创建所有线程的额外开销只是执行可数的因素,这可能是减速的原因。 Parallel.ForEach并非一揽子增加业绩;无论是否可能阻止要为每个元素完成的操作,都需要对其进行权衡。

例如,如果您要创建Web请求或其他内容而不是简单地写入控制台,则并行版本可能会更快。实际上,简单地写入控制台是一个非常快速的操作,因此创建线程并启动它们的开销会变慢。

答案 3 :(得分:4)

正如之前的作者所说,Parallel.ForEach存在一些与开销相关的开销,但这并不是您无法看到绩效改善的原因。 Console.WriteLine是一个同步操作,因此一次只能运行一个线程。尝试将身体更改为非阻塞状态,您将看到性能提升(只要身体中的工作量足以超过开销)。

答案 4 :(得分:0)

我喜欢Salomons的答案,并且想补充一点,您还有

的额外开销
  1. 分配代表。
  2. 打电话给他们。