【问题标题】:Why isn't this Parallel.ForEach loop improving performance?为什么这个 Parallel.ForEach 循环不能提高性能?
【发布时间】:2011-11-11 16:18:54
【问题描述】:

我有以下代码:

           if (!this.writeDataStore.Exists(mat))
            {
                BlockingCollection<ImageFile> imageFiles = new BlockingCollection<ImageFile>();
                Parallel.ForEach(fileGrouping, fi => DecompressAndReadGzFile(fi, imageFiles));


                this.PushIntoDb(mat, imageFiles.ToList());
            }

DecompressAndReadGzFile 是包含此方法的同一类中的静态方法。根据方法名称,我正在解压缩和读取 gz 文件,其中很多,即最多 1000 个,因此并行化的开销是值得的它的好处。但是,我没有看到好处。当我使用 ANTS 性能分析器时,我看到它们运行的​​时间与没有发生并行化的时间完全相同。我还使用进程资源管理器检查了 CPU 内核,看起来可能在两个内核上完成了工作,但一个内核似乎正在完成大部分工作。就让 Parallel.ForEach 并行解压缩和读取文件而言,我不明白什么?

更新问题:从文件列表中读取信息的最快方法是什么?

问题(简​​化):

  1. 有大量 .gz 文件 (1200)。
  2. 每个文件都有一行包含“DATA:”,位置和行号不是静态的,可能因文件而异。
  3. 我们需要检索“DATA:”之后的第一个数字(为了简单起见)并将其存储在内存中的对象中(例如列表)

在最初的问题中,我使用的是 Parallel.ForEach 循环,但我的 CPU 似乎没有超过 1 个内核。

【问题讨论】:

  • DecompressAndReadGzFile有同步吗?
  • 我不知道。虽然有一个对 imageFiles.Add 的调用,它会根据我的理解自动添加一个锁。

标签: c# .net multithreading


【解决方案1】:

线程是否有可能大部分时间都在等待 IO?通过一次读取多个文件,您可能会使磁盘抖动超过一次操作。您可以通过使用单线程顺序读取来提高性能,然后将 CPU 绑定的解压缩分配给单独的线程......但您实际上可能会发现,无论如何,您实际上只需要一个线程执行解压缩,如果磁盘比解压过程本身要慢。

对此进行测试的一种方法是先将需要解压缩的文件复制到 ramdisk 上,然后仍然使用您当前的代码。我怀疑你会发现你受 CPU 限制,并且所有处理器几乎一直都很忙。

(您还应该考虑如何处理解压缩的文件。您是否将它们写回磁盘?如果是这样,那么您可能基本上是在等待一个抖动的磁盘。)

【讨论】:

  • 我没有将解压后的文件写入磁盘。我正在使用 GZipStream 将压缩文件读入内存,创建一个 TextREader 以提取我需要的内容,并将其放入上述代码中的 imageFiles 集合中。不过,我可能会尝试您的 RAM 磁盘建议。
  • @Seth:请注意,ramdisk 建议实际上是只是来验证您是否受 IO 限制而不是 CPU 限制。如果是这种情况,那么您最终只会将成本转移到“将数据复制到 ramdisk”阶段。
  • 还记得几年前那些硬盘驱动器涡轮增压器软件驱动程序吗?他们通过压缩内存中的数据,然后将压缩后的数据写入磁盘,使磁盘 I/O 更快。
【解决方案2】:

您的静态方法是否有可能在其调用之间共享任何全局资源。 因为在那种情况下,这个静态方法将被顺序调用并且没有并行的好处。 你能把你的fileGrouping类代码吗?

【讨论】:

    猜你喜欢
    • 2017-11-19
    • 2010-12-09
    • 2019-08-06
    • 2020-08-25
    • 2015-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多