低效的Parallel.For?

时间:2012-11-27 16:30:06

标签: c# c#-4.0 task-parallel-library

我在我的代码中使用并行for循环在大量实体(12,000)上运行一个长时间运行的进程。

进程解析一个字符串,经过一些输入文件(我已经读过,考虑到基于IO的东西的数量,线程的好处可能会有问题,但它似乎在其他地方加速了)并输出一个匹配的结果。

最初,这个过程进展得非常快 - 但最终会慢慢爬行。它可能只是打了一些特别棘手的输入数据,但这似乎不太可能看得更近。

在循环中,我添加了一些调试代码,在开始/结束迭代时打印“已启动处理:”和“完成处理:”,然后编写一个程序,将开始和结束配对,最初为了查找哪个ID导致崩溃。

但是,查看不匹配ID的数量,看起来该程序一次处理超过400个不同的实体。这似乎是,由于IO数量众多,它可能是问题的根源。

所以我的问题是(这些):

  • 我是否正确地解释了无与伦比的ID,或者是否有一些聪明的东西会在幕后发现,甚至是一些明显的东西?
  • 如果你同意我发现的是正确的,我怎么能限制它旋转的数量并立即进行呢?

我意识到这可能是一个有点不正统的问题,如果没有代码可能会很难回答,但是感谢任何帮助,如果您有任何其他信息,请在评论中告诉我。

2 个答案:

答案 0 :(得分:2)

如果没有看到某些代码,我可以猜出你问题的答案:

  • 不匹配的ID向我表明正在对正在处理该数据的线程进行去优先级排序。这可能是由于IO或线程池试图优化,但是看起来如果你是强大的IO绑定那么这很可能是你的问题。
  • 我会看一下Parallel.For,特别是使用ParallelOptions.MaxDegreesOfParallelism将最大任务数量限制为合理数量。我建议尝试使用试验和错误来确定最佳度数,从您拥有的处理器核心数开始。
祝你好运!

答案 1 :(得分:0)

让我首先确认从硬盘驱动器同时读取2个文件确实是一个非常糟糕的主意(至少直到那里的大多数HD都有SSD),更不用说整个事情使用的数字了。 。 并行性的使用用于使用实际可并发化的资源(CPU功率)来优化处理。如果你从硬盘驱动器中读取了进程读取,那么你将失去大部分好处。

即便如此,即使CPU功率也不容易无限制的并行化。普通的桌面CPU可以同时运行多达10个线程(显然取决于模型,但这是数量级)。

所以有两件事

  • 首先,我假设您的实体使用所有文件,但是您的文件不是太大而无法加载到内存中。如果是这种情况,您应该将文件读入对象(即进入内存),然后使用这些对象对您的实体进行并行处理。如果没有,你基本上依靠硬盘的缓存来在每次需要时不重读你的文件,你的硬盘缓存远远小于你的内存(1000倍)。

  • 第二,你不应该在12.000项目上运行Parallel.For。 Parallel.For实际上(尝试)创建了12.000个线程,这实际上比10个线程更糟糕,因为并列化会产生很大的开销,而且你的CPU根本不能从中受益,因为它不能运行超过10个线程。一次10个线程。

您应该使用更有效的方法,即IEnumerable<T>.AsParallel()扩展名(随.net 4.0一起提供)。这个将在运行时确定要运行的最佳线程数,然后将可枚举分成多个批次。基本上,它可以为您完成任务 - 但它也会产生很大的开销,所以只有在处理一个元素对CPU来说实际上是昂贵的时候它才有用。

根据我的经验,使用任何并行的东西应始终进行评估,而不是在现实生活中使用它,即通过实际分析您的应用程序。不要以为它会更好地运作。