首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Parallel.For System.OutOfMemoryException

Parallel.For System.OutOfMemoryException
EN

Stack Overflow用户
提问于 2010-06-06 20:48:54
回答 1查看 1.9K关注 0票数 2

我们有一个相当简单的程序,用于创建备份。我试图将其并行化,但在AggregateException中获得了一个AggregateException。一些源文件夹相当大,程序在启动后大约40分钟内不会崩溃。我不知道从哪里开始查找,所以下面的代码是几乎完全正确的所有代码、代码、无目录结构和异常日志代码的转储。对从哪里开始找有什么建议吗?

代码语言:javascript
运行
复制
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更改为常规程序。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2010-06-06 21:57:23

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

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

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

  • 磁盘头将到处乱动。
  • 您的磁盘\OS缓存可能经常失效。

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

更新

在回答您的评论时,如果您在较小的数据集中使用多个线程来加快速度,那么您可以尝试降低并行进程中使用的最大线程数。

代码语言:javascript
运行
复制
ParallelOptions options = new ParallelOptions { MaxDegreeOfParallelism = 2 };

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

但是请记住,在一般情况下,磁盘重击可能会否定并行化带来的任何好处。利用它来衡量你的结果。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2985842

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档