gpt4 book ai didi

c#-3.0 - Parallel.For System.OutOfMemoryException

转载 作者:行者123 更新时间:2023-12-04 06:52:01 25 4
gpt4 key购买 nike

我们有一个相当简单的程序用于创建备份。我正在尝试对其进行并行化,但在 AggregateException 中收到 OutOfMemoryException。一些源文件夹相当大,程序在启动后大约 40 分钟内不会崩溃。我不知道从哪里开始寻找,所以下面的代码是所有代码的近乎精确的转储,代码没有目录结构和异常记录代码。关于从哪里开始寻找的任何建议?

using System;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;

namespace SelfBackup
{
class Program
{

static readonly string[] saSrc = {
"\\src\\dir1\\",
//...
"\\src\\dirN\\", //this folder is over 6 GB
};
static readonly string[] saDest = {
"\\dest\\dir1\\",
//...
"\\dest\\dirN\\",
};

static void Main(string[] args)
{
Parallel.For(0, saDest.Length, i =>
{
try
{
if (Directory.Exists(sDest))
{
//Delete directory first so old stuff gets cleaned up
Directory.Delete(sDest, true);
}

//recursive function
clsCopyDirectory.copyDirectory(saSrc[i], sDest);
}
catch (Exception e)
{
//standard error logging
CL.EmailError();
}
});
}
}

///////////////////////////////////////
using System.IO;
using System.Threading.Tasks;

namespace SelfBackup
{
static class clsCopyDirectory
{
static public void copyDirectory(string Src, string Dst)
{
Directory.CreateDirectory(Dst);

/* Copy all the files in the folder
If and when .NET 4.0 is installed, change
Directory.GetFiles to Directory.Enumerate files for
slightly better performance.*/
Parallel.ForEach<string>(Directory.GetFiles(Src), file =>
{
/* An exception thrown here may be arbitrarily deep into
this recursive function there's also a good chance that
if one copy fails here, so too will other files in the
same directory, so we don't want to spam out hundreds of
error e-mails but we don't want to abort all together.
Instead, the best solution is probably to throw back up
to the original caller of copy directory an move on to
the next Src/Dst pair by not catching any possible
exception here.*/
File.Copy(file, //src
Path.Combine(Dst, Path.GetFileName(file)), //dest
true);//bool overwrite
});

//Call this function again for every directory in the folder.
Parallel.ForEach(Directory.GetDirectories(Src), dir =>
{
copyDirectory(dir, Path.Combine(Dst, Path.GetFileName(dir)));
});
}
}

线程调试窗口在异常发生时显示 417 个工作线程。

编辑:复制是从一台服务器到另一台服务器。我现在正在尝试将最后一个 Paralell.ForEach 更改为常规 foreach 来运行代码。

最佳答案

在这里做一些猜测,因为我还没有从对您的问题的评论中得到反馈。

我猜测这里发生了大量的工作线程,因为操作(一个操作是在并行 foreach 上执行的工作单元)花费的时间超过指定的时间,因此底层 ThreadPool 正在增加线程的数量.这将发生,因为 ThreadPool 遵循增长池的算法,以便新任务不会被现有的长时间运行的任务阻塞,例如如果我当前的所有线程都忙了半秒钟,我将开始向池中添加更多线程。但是,如果所有任务都长时间运行,并且您添加的新任务将使现有任务运行时间更长,您就会遇到麻烦。这就是为什么您可能会看到大量工作线程的原因 - 可能是因为磁盘抖动或网络 IO 速度慢(如果涉及网络驱动器)。

我还猜测文件正在从一个磁盘复制到另一个磁盘,或者它们正在从一个位置复制到同一磁盘上的另一个位置。在这种情况下,向问题添加线程不会有太大帮助。源磁盘和目标磁盘只有一组磁头,因此试图让它们一次做多件事实际上可能会减慢速度:

  • 磁盘磁头会四处晃动。
  • 您的磁盘\操作系统缓存可能经常失效。

  • 对于并行化来说,这可能不是一个大问题。

    更新

    为了回答您的评论,如果您在较小的数据集上使用多个线程获得加速,那么您可以尝试降低并行 foreach 中使用的最大线程数,例如
    ParallelOptions options = new ParallelOptions { MaxDegreeOfParallelism = 2 };

    Parallel.ForEach(Directory.GetFiles(Src), options, file =>
    {
    //Do stuff
    });

    但请记住,在一般情况下,磁盘抖动可能会抵消并行化带来的任何好处。玩弄它并衡量你的结果。

    关于c#-3.0 - Parallel.For System.OutOfMemoryException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2985842/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com