繁体   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