【问题标题】:How to parallelize an IEnumerable with a slow yield (which renders PLINQ useless)?如何以缓慢的产量并行化 IEnumerable(这使得 PLINQ 无用)?
【发布时间】:2017-12-05 19:48:03
【问题描述】:

我在寻找正确并行处理 IEnumerable 的方法时遇到了一些麻烦,其中每个项目的实际生成需要相当长的时间,因此每次调用 MoveNext 时都会有效地锁定一点在读者方面。

这是我的场景:

我有一个采用IEnumerable<(float[], float[])> 的方法(具体类型在这里并不重要),我需要计算这些项目,将它们分成固定侧的批次,然后处理每个批次。

假设我已经准备好分区代码(请参阅this answer here)以及处理每个单独分区的代码。

问题在于,正如我所说,从初始列表中产生每个值都涉及一些 IO/CPU 操作(通常会读取图像,处理它并返回这两个矩阵),所以即使是:

var items = dataset.AsParallel().Partition(size).ToArray().AsParallel().Select(partition =>
{
    // Process the partitions here..
    return partition;
}).ToArray(); // Two AsParallel calls because I'm doing two selections one after the other

我得到大约 25% 的 CPU 使用率(我有一个 8 核 AMD FX-8350),因为我猜是第一个列表中项目的实际生成导致枚举速度变慢,甚至在到达第一个AsParallel 电话。

我在想一个可能的解决方案是要求此方法的用户改为提供IEnumerable<Func<(float[], float[])>>,因为这样可以让我的方法轻松地并行处理这些元素。

我的问题是:这是唯一可能的解决方案,还是有另一种方法可以并行枚举“锁定”IEnumerable,而不会导致减速导致每个项目不并行产生?

谢谢!

编辑:澄清一下,我没有在第一个 IEnumerable 中编写实际代码,这取决于相关库的用户,他们将输入它自己的IEnumerable 用于库拆分成批次并继续工作。 我希望有一个替代 Func 委托的原因之一是,在用户方面,只返回一个元组比必须显式返回一个懒惰地计算整个函数的函数更容易和更直观东西。

【问题讨论】:

  • 似乎您需要改进 ienumerable,而不是您的代码。
  • @DanielA.White IEnumerable 是用户提供的,不是我写的。这基本上是用户将其训练数据集输入到库中的方式,这里我只是将其转换为批量使用。我只是假设在用户端实际生成各种训练样本(读取文件等)通常会涉及一些昂贵的工作。
  • 没有办法,因为 IEnumerable 本质上是顺序的。你不能以某种方式强制一堆顺序代码并行执行(当然不修改它)。
  • @Evk 是的,我早就料到了。问题是,要求用户手动将每个样本的所有代码包装在 lambda 中似乎有点笨拙,而且比我想要的使用起来更不直观,在用户方面至少有更好的方法吗?特别是因为在使用这样的函数时通常不能使用隐式 var,因为编译器通常无法确定将 lambda 转换为的确切类型(在这种情况下为 Func(float[,] etc..。谢谢!
  • 致投反对票的用户,“太宽泛”?真的吗?我提供了上下文描述、代码示例,并详细解释了我在这里尝试做什么以及到目前为止我得到了什么。怎么会认为这个问题太宽泛了?

标签: c# linq parallel-processing plinq


【解决方案1】:

恐怕你不能。如果最初的IEnumerable 很慢,那么无论您在并行化和处理能力方面使用多少资源,您都无能为力,以使其更快。最好的情况是尽可能少地添加。但是还是很慢。

解决方案是看看是否可以通过任何方式加速原始的初始序列。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-14
    • 1970-01-01
    • 1970-01-01
    • 2014-08-04
    • 1970-01-01
    相关资源
    最近更新 更多