【问题标题】:Order of a Parallell Loop not being respected未遵守并行循环的顺序
【发布时间】:2014-11-28 04:16:38
【问题描述】:

我正在将大量文件从一台服务器复制到其他几台服务器。

我有一个具有顺序的复制操作列表,因此服务器 a 的文件位于列表的第一位,服务器 b 的文件位于列表的末尾。

我在列表中使用 AsParallel.AsOrdered() 以确保首先将文件复制到第一台服务器,然后仅当线程空闲到第二台服务器时。

它似乎无法正常工作,因为它会同时将文件复制到两个服务器,我是否遗漏了什么,是否有更好的方法来编写此代码。我检查了大文件以真正看到顺序,它似乎没有反映列表顺序

var dotheCopy = copy.ToArray().OrderBy(a => a.GroupId);

var copyList = new List<CopyOps>();

foreach (var x in dotheCopy)
{
    ... some validation code 
    copyList.Add(x);
}

copyList.AsParallel().AsOrdered().WithDegreeOfParallelism(5)
    .ForAll(x => this.DoTheCopy(x));

【问题讨论】:

  • 您的实际目标似乎是按顺序处理您的项目,但以 5 个为一组,对吗?
  • 我们需要做的是首先复制到第一台服务器,但随着线程变得可用开始复制第二台服务器,我们的最大并行度为 5

标签: .net parallel-processing task-parallel-library parallel.foreach


【解决方案1】:

AsOrdered 不保证执行顺序。它保证 结果 将被排序。

Enumerable.Range(0, 3).AsParallel().Select(x => x); // 3,1,2,

Enumerable.Range(0, 3).AsParallel().AsOrdered().Select(x => x); // 1,2,3

由于ForAll 不返回任何内容,因此将其与AsOrdered 结合是无用的。

您的实际目标似乎是按顺序处理您的项目,但每批 5 个,对吗?换句话说,您需要节流。如果是这样,您可以使用来自 TPL 数据流的ActionBlock&lt;T&gt;

var block = new ActionBlock<CopyOps>(DoTheCopy, 
        new ExecutionDataflowBlockOptions
         {
            MaxDegreeOfParallelism = 5
         });

var tasks = copyList.Select(item => block.SendAsync(item));

await Task.WhenAll(tasks);

或者,一个更简单的方法,如果阻塞主线程不是问题

Parallel.ForEach(copyList,
                 new ParallelOptions { MaxDegreeOfParallelism = 5 },
                 DoTheCopy);

【讨论】:

  • 我们需要做的是首先复制到第一台服务器,但随着线程变得可用开始复制第二台服务器,我们的最大并行度为 5
  • 我假设切换逻辑在 DoTheCopy 方法中的某个地方,老实说,我不明白这与问题有什么关系。为什么物品必须按顺序处理?如果所有项目都需要 1 秒发送,而这一个文件需要 10 分钟怎么办?其他 4 个线程应该坐在那里等待还是继续抽其他文件?
  • @dcastro 您的声明“AsOrdered 不保证执行顺序。它保证结果是有序的。”似乎暗示可能存在最坏的情况,我无法开始枚举结果,除非原始序列中的所有元素都已处理(当然是并行的).. 对吗?您能否提供一些其他参考来支持此声明?
  • @dcastro 我们需要优先考虑服务器 a 上存在的所有文件,当所有文件都在那里复制并且线程可用时,我想开始复制到服务器 B,我希望这是有道理的: )。目的地内置在 CopyOps 类中,并首先使用服务器 a 进行排序,然后在列表末尾是服务器 b。
  • 这是实现目标的更好方法吗? Parallel.For( 0, copyList.Count, new ParallelOptions { MaxDegreeOfParallelism = 5 }, index =&gt; this.DoTheCopy(copyList[index]));
【解决方案2】:

这是来自 MSDN 的一些文档 -

Order Preservation in PLINQ

ForAll&lt;TSource&gt; - 源序列排序时的结果 - 非确定性并行执行”

看来ForAll 不遵守命令。

【讨论】:

  • 谢谢,你对如何重构代码有什么建议吗?
  • @Jeepers 请问这个订单的具体原因是什么?如果必须,您是否可以分两批进行复制(即,一个接一个地(并行)处理两个列表)。假设列表有足够的工作要做,通过将原始列表一分为二,您只会失去一点并行性。这是我能想到的针对您的原始问题的最简单(最小调整)的解决方案。最后但并非最不重要的一点是,考虑使用异步模式进行 IO 操作,但这超出了这个问题的详细范围.
猜你喜欢
  • 1970-01-01
  • 2011-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多