并行循环的顺序不受尊重

时间:2014-11-27 19:09:27

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

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

我有一个包含订单的复制操作列表,因此服务器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));

2 个答案:

答案 0 :(得分:4)

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 Dataflow中的ActionBlock<T>

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);

答案 1 :(得分:2)

以下是MSDN的一些文档 -

Order Preservation in PLINQ

ForAll<TSource> - 订购源序列时的结果 - 并行执行非确定性”

似乎ForAll不尊重订单。