【问题标题】:Parallel.Foreach as fast / slow as normal ForEachParallel.Foreach 与正常 ForEach 一样快/慢
【发布时间】:2011-02-04 15:58:56
【问题描述】:

更新:我使用线程将循环拆分为内核数量(在我的案例中为 8 个),并且完整的循环在 1 秒内完成。所以问题不在于线程的操作速度并不快。为什么 Parralel Extension 在这种情况下会失败?

大家好。我想用 Parrallel.Foreach 转换我的 ForEach。 问题是,并行化几乎没有给我带来任何好处。

原文:

foreach (Entities.Buchung buchung in buchungen) {
    Int32 categoryID = manager.GetCategoryID(new Regelengine.Booking(buchung)); // Average 4ms
    buchung.Category = categoryID.ToString();
}

平行:

System.Threading.Tasks.Parallel.ForEach(buchungen, buchung => {
    Int32 categoryID = manager.GetCategoryID(new Regelengine.Booking(buchung));
    buchung.Category = categoryID.ToString();
});

结果:

---------------------------
Stopwatched Results for 1550 entries in the List:
---------------------------
Parallel.Foreach 00:00:07.6599066
Average Foreach: 00:00:07.9791303

也许问题是,循环中的实际动作是如此之短?但是没有人能告诉我,在 Intel I7 上并行 1550 次操作不会节省任何时间。

【问题讨论】:

  • Regelengine 的东西可能有锁。
  • 问题是:语句中的方法是否得益于并行性?我不知道的下一件事是 GetCategoryID 的作用。是否存在可能成为瓶颈并阻止代码使用多线程的数据库调用。
  • manager.GetCategoryID 方法中发生了什么? ctor new Regelengine.Booking 会发生什么?
  • 没有数据库或网络调用。构造函数将我的实体转换为用于调用 manager.GetcategoryID() 的实体,该实体在 .COM 库上运行

标签: c# multithreading foreach parallel-processing


【解决方案1】:

只有 一个 资源您可以通过使用 Parallel.For: CPU 周期来利用。当您有 N 个内核时,理论上您可以将代码加速 N 倍。然而,需要的是实际上 CPU 周期是代码中的约束。除非您执行计算量大的代码,否则这种情况并不常见。其他限制是硬盘速度、网络连接、数据库服务器,在某些情况下还有内存总线的带宽。你只有其中一个,Parallel.For 不能神奇地给你另一个磁盘。

测试 Parallel.For 是否会加速您的代码非常简单。只需在不进行并行化的情况下运行代码并观察 Taskmgr.exe 或 Perfmon 中的 CPU 负载。如果一个内核没有以 100% 的速度运行,那么您的代码不受计算限制。如果它以 10% 的速度运行,那么无论你有多少核心,你都只能希望它占用 90% 的时间。您可以通过重叠 I/O 等待时间和处理时间来获得,两个线程将完成。

【讨论】:

    【解决方案2】:

    您应该考虑的问题是:

    • 启动线程的开销是多少?
    • 我的线程安全(锁)的开销是多少?
    • 实际的瓶颈在哪里?多线程真的有帮助吗?

    最后一个是您最大的考虑因素。例如,如果你最大化你的 i/o 通道,世界上所有的线程都不会蹲。那么您的任务是 CPU 受限还是 I/O 受限?

    【讨论】:

    • 线程创建不应该足够昂贵来创建这种效果。用说 where 来说 locks 是没有用的。
    • 感谢您的回答,但我现在使用普通线程手动拆分循环,它很快就完成了。所以问题不在于线程本身,而在于 ForeachLoop?
    【解决方案3】:

    我认为你是对的,它看起来确实有点太短,不值得使用并行 foreach。仅当我知道在 foreach 中将发生一些需要时间或可能需要时间的重要事情时,我才使用并行 foreach,例如数据库连接或如果我向 Web 服务发送大量数据。如果它只是在服务器上处理信息,就像只是从已经加载到内存中的集合中获取 ID,那么它真的不值得。

    【讨论】:

      【解决方案4】:

      如果您没有可用的内核可供使用,并行性不会更快。所以当我看到这样的代码时,我的第一个想法是你有其他线程在运行。

      也可能是工作量。同步逻辑不是免费的,每次迭代都没有多大作用。考虑查看 Parallel.ForEach 的其他重载,以了解您可以调整的选项。

      也可以尝试使用 Parallel.For。您不能以并行方式从 IEnumerable 中读取,但可以使用索引从 IList 中读取。

      【讨论】:

        【解决方案5】:

        首先,1550 并不多。例如,按顺序对包含这么多元素的数组进行排序通常比并行排序要快。这一切都取决于操作。

        其次,GetCategoryID 是做什么的?它使用锁吗?就此而言,Regelengine.Booking 构造函数是否?

        7 秒的总运行时间表明该操作足够慢,应该受益于并行化。另一方面,您的代码似乎表明这里实际上没有进行很多处理。您很可能是从磁盘或数据库加载数据。在这两种情况下,这是并行化(几乎)无能为力的瓶颈。并发处理使您的代码更快只有如果它受计算限制。

        但您没有提供足够的信息来确定这一点。

        【讨论】:

          猜你喜欢
          • 2011-08-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-04-16
          • 1970-01-01
          • 1970-01-01
          • 2021-10-15
          相关资源
          最近更新 更多