【C#】Parallel.ForEach导致内存不足问题解决方案

【C#】Parallel.ForEach导致内存不足问题解决方案其中第一个参数Datas是我们的数据集合,第二个参数为一个action委托,用来对集合中的数据进行处理或者计算,如果使用适当,能够有效提高计算效率,但是在使用不当的情况下就可能会出现“OutofMemory”的错误,通过在网上搜索,最终在StackOverflow上找到了对这个问题解释的比较好的一个回答,现分享在这里。如果你的任务不是CPU密集型或者CPU的利用率在最大并行数量下不是线性增长的,那么建议你在使用Parallel.ForEach的时候不要一次性开启太多任务。

在对大量数据进行处理或计算的时候,使用并行提高效率是经常使用的做法,在C#中提供了Parallel.ForEach()方法代替foreach来进行并行处理,提高效率,它使用方法很简单,伪代码如下:

using System.Threading.Tasks;

Parallel.ForEach(Datas,(data)=>
{
    //对data进行计算或处理
}
);

其中第一个参数Datas是我们的数据集合,第二个参数为一个action委托,用来对集合中的数据进行处理或者计算,如果使用适当,能够有效提高计算效率,但是在使用不当的情况下就可能会出现“Out of Memory”的错误,通过在网上搜索,最终在StackOverflow上找到了对这个问题解释的比较好的一个回答,现分享在这里。

问题分析及解决方案

Parallel.ForEach的默认选项只有当任务时CPU密集型且CPU利用率线性增长时才有很好的表现,当任务是CPU密集型时,一切都很完美。如果你有一个四核的CPU且没有其他进程在运行,那么Parallel.ForEach可以使用所有四个处理器。如果你有一个四核CPU并且同时有一个进程在使用一个完整的处理器,那么Parallel.ForEach大约会使用三个处理器。

但是如果任务不是CPU密集型,那么Parallel.ForEach将会一直开启新任务,努力维持CPU的满载运行,但是无论多少任务在并行执行,总会有未使用的CPU资源所以它就会不断创建新任务。

那么怎么判断你的任务是否是CPU密集型的呢?最好是通过观察就能够知道,比如你正在进行分解质因数的操作,那很显然这就是一个CPU密集型任务。但是大部分情况下都很难一眼看出是否是CPU密集型操作,所以一般情况下的经验方法是通过限制最大并行数量(ParallelOptions.MaximumDegreeOfParallelism)并观察程序的表现,如果你的任务是CPU密集型你将会看到(四核情况):

  • ParallelOptions.MaximumDegreeOfParallelism = 1 :CPU使用率25%或使用一个CPU
  • ParallelOptions.MaximumDegreeOfParallelism = 2 :CPU使用率50%或使用两个CPU
  • ParallelOptions.MaximumDegreeOfParallelism = 4 :CPU使用率100%或使用所有CPU

当你观察到如上的情况,那么你就可以使用默认的Parallel.ForEach选项并且得到很好的结果。线性的CPU利用率意味着良好的任务调度。

但是当我在Intel I7处理器上运行你的示例代码时,无论我设置多大的最大并行数,我只能得到20%的CPU利用率,为什么会这样呢?因为分配的内存太多导致GC阻塞了线程。显然,这个程序是资源密集型的,而这里的资源就是—内存!

同样,对数据库服务器执行长时间运行查询的IO密集型任务也永远无法有效利用本地计算机上的所有可用CPU资源。在这种情况下,任务调度程序无法“知道何时停止”启动新任务。

如果你的任务不是CPU密集型或者CPU的利用率在最大并行数量下不是线性增长的,那么建议你在使用Parallel.ForEach的时候不要一次性开启太多任务。最简单的方法是为并行数MaxDegreeOfParallelism指定一个数值(设置ForEach的第二个参数ParallelOptions),允许对重复的I/O密集型任务进行一定程度的并行处理,但不要太多,以免本地计算机对资源的需求过大,或使远程服务器负担过重。为了获得最佳设置参数,需要不断反复试验。

static void Main(string[] args)
{
    Parallel.ForEach(CreateData(),
        new ParallelOptions { MaxDegreeOfParallelism = 4 },
        (data) =>
            {
                data[0] = 1;
            });
}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/35680.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注