【问题标题】:CPU & Memory spikes, during Parallel.ForEachParallel.ForEach 期间的 CPU 和内存峰值
【发布时间】:2018-03-03 05:56:45
【问题描述】:

我正在构建一个用于复制文件和文件夹的应用程序,还有一些选项,但在此问题中没有使用这些选项。

有问题的函数遍历目录中的每个文件,然后将文件复制到相同目录的新位置(因此它保留嵌套的文件结构)。

应用程序是一个 Windows 窗体,由于同时写入文本框的问题,我将并行函数包围在 Task.Factory.StartNew() 中,从而解决了该问题。

Task.Factory.StartNew(() =>
{
    Parallel.ForEach(Directory.GetFiles(root, "*.*", SearchOption.AllDirectories), newPath =>
    {
        try
        {
            File.Copy(newPath, newPath.Replace(root, destination), false);
            WriteToOutput("recreated the file '" + newPath.Replace(root, destination) + "'");                                
         }
         catch (Exception e)
         {
             WriteToOutput(e.Message);
         }
     });
});

运行时,诊断工具每隔几秒就会显示一次峰值。我怎样才能“平衡”这些尖峰并使性能保持一致?我还在为每个移动的文件写入屏幕,并且每隔 20/25 个文件之间会有一个明显的秒左右的暂停。

以下屏幕截图是来自诊断工具的示例。

【问题讨论】:

  • 尝试复制线程效果的一个好方法是使用robocopy /MT:n 功能在一些典型的源驱动器和目标驱动器配置之间复制一组有代表性的数据。我想你会发现n > 2n == 1 快,但是会有一个收益递减点。我的经验是/MT:4 过去是一个不错的选择,但对于很多小文件,/MT:8 可能会更好。这将为您提供一些线索,您可以应用这些线索来选择您的应用程序应该使用多少线程以及何时使用。也许你想让它可配置?

标签: c#


【解决方案1】:

您的工作主要受 IO 限制,而不是 CPU 限制。在大多数情况下,您没有任何工作需要 CPU 完成。您只是在等待硬盘驱动器完成工作。 CPU 中的尖峰只是磁盘完成操作后的一小段时间,CPU 试图弄清楚接下来要做什么,这需要很少的时间,因此您会看到尖峰,而不是平台期。

【讨论】:

  • 啊,好吧,所以这些尖峰不需要担心?
【解决方案2】:

我很关心这句话:

由于同时写入文本框的问题,我将并行函数包围在 Task.Factory.StartNew() 中,从而解决了该问题

老实说,我怀疑这是否解决了问题。大概是把它藏起来了。您似乎没有在等待或检查任务,因此您没有观察到任何异常。短暂的 CPU 峰值和输出延迟很容易由某种堆栈展开引起。

如果您在从工作线程更新 UI 时遇到问题,请确保您了解 Invoke 的用途并确保您正在使用它。然后摆脱StartNew,或者确保您正在处理任何异常。

【讨论】:

  • 好的,我会在这里进一步研究我的用法。老实说,解决这个问题似乎有点容易了。也感谢您的参考。
【解决方案3】:

您正在做的是用许多并行文件读取请求来按下磁盘。好吧,磁盘和任何其他 I/O 设备一样,在该模式下无法正常工作。

一方面,如果您正在读取 HDD,那么它肯定无法响应并行请求,因为它必须同时将读取头移动到多个位置。

即使使用 SDD,设备也无法以 CPU 可以请求的相同速率响应请求。

无论如何,磁盘肯定无法匀速返回数据。许多文件读取请求将永久挂起(以 CPU 时间衡量),使这些任务被阻塞。这就是为什么在使用许多并行操作冲击磁盘时性能不均衡的原因。

当尝试处理许多文件时,您可能会选择分配一个任务来读取它们,然后并行处理加载的数据。想想那个设计。 I/O-bound 任务将只有一个,并且不会被超过必要的阻塞。这将使驱动器以当时可以达到的最大速度返回数据。显然,受 CPU 限制的任务将是非阻塞的,因为在任何任务启动时它们的数据已经在内存中。我希望这种设计能够提供流畅的性能。

【讨论】:

  • 好的,谢谢您的回答。我正在从 SSD 读取并写入 HDD,我什至没有考虑 HDD 的物理限制。因此,由于我没有处理,从不打开文件的意义上说,并且所有任务都是 IO 密集型的,你会说使用并行循环是不必要的吗?
  • 在这种情况下,是的,我认为当您考虑所有影响时,并行循环正在造成损害。您应该衡量效果,但我的猜测是您只需要一项阅读任务和一项写作任务。在相关的说明中,两个任务将比一个任务执行得更好,因为仍有 一些 CPU 工作需要完成。
  • NTFS 维护要在磁盘上执行的 I/O 操作队列,并将重新排序操作以优化总吞吐量。当文件大小相当随机且大多很小时,拥有多个读取器/写入器并没有什么坏处,并且通常可以加快速度。看看robocopy /mt:1robocopy /mt:4 之间的性能差异就知道了。
猜你喜欢
  • 2014-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多