CPU&在Parallel.ForEach期间内存峰值

时间:2018-03-02 21:44:35

标签: c#

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

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

该应用程序是一个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文件之间有一个明显的第二次停顿。

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

enter image description here

3 个答案:

答案 0 :(得分:5)

您的工作主要是IO绑定,而不是CPU绑定。你不会拥有任何CPU的工作来完成大部分时间。您只是在等待硬盘驱动器 的工作。 CPU完成一次操作后,CPU中的峰值只是很短的一段时间,CPU试图找出下一步要求它做什么,这需要很少的时间,因此为什么你会看到尖峰,而不是高原。

答案 1 :(得分:3)

我担心这句话:

  

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

老实说,我怀疑修复了这个问题。它可能隐藏了它。您似乎没有等待或检查任务,因此您没有观察到任何异常。短暂的CPU峰值和输出延迟很容易引起某种堆栈的放松。

如果您无法从工作线程更新UI,请确保了解Invoke的用途,并确保使用它。然后摆脱StartNew,或确保你正在处理任何例外。

答案 2 :(得分:1)

您正在做的是并行地按下具有许多文件读取请求的磁盘。好吧,与任何其他I / O设备一样,磁盘在该模式下也不能正常工作。

首先,如果您正在阅读硬盘,那么它肯定无法回答并行请求,因为它必须同时将阅读头移动到多个位置。

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

在任何情况下,磁盘肯定无法以统一的速度返回数据。许多文件读取请求将在整个永恒期间(以CPU时间测量)处于待处理状态,从而阻止这些任务。这就是为什么在使用许多并行操作来攻击磁盘时性能不均匀的原因。

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