Parallel.ForEach丢失数据

时间:2016-03-18 13:18:02

标签: c# parallel.foreach

Parallel.ForEach有助于提高性能,但我看到数据丢失。

尝试 - 变量结果,processedData为ConcurrentBag<IwrRows>

1)

Parallel.ForEach(results, () => new ConcurrentBag<IwrRows>(), (n, loopState, localData)    =>
{
 return ProcessData(n); // ProcessData complicated business logic
}, (localData) => AddRows(localData, processedData, obj)
);

2)

await Task.Run(() => Parallel.ForEach(results, item =>
        {
            ProcessData(item, processedData);  
        }));

3)

Parallel.ForEach(results, item =>
 {
 ProcessData(item, processedData);
 });

所有人都失去了一些行。

当我使用foreach块时,它会始终返回相同的值,但速度要慢4倍。

foreach (var item in results)
        {
            // ProcessData returns a List<IwrRows>
            processedData.AddRange(ProcessData(item));
        }

不确定我在这里缺少什么。

结果 - 51112 Foreach返回41316行。 ForeachParallel返回41308或41313或41314随每次运行而变化

4 个答案:

答案 0 :(得分:6)

您似乎对结果感到困惑,并将它们重新置于一个连贯的列表中。您可以使用PLinQ,因此您不必担心结果容器是线程安全的:

var processedData = yourData.AsParallel().Select(ProcessData).ToList();

答案 1 :(得分:4)

你的问题似乎在:AddRows(localData,processedData,obj)。此方法可能是将数据添加到非线程安全的列表中。您应该添加到线程安全列表或围绕添加数据进行一些同步。

答案 2 :(得分:0)

在2)中使用await Task.Run是没用的。

Foreach returns 41316 rows back Results - 51112 问题不在Parallel.ForEach中,而在于您的添加/处理机制。请记住,即使ConcurrentBag保证其上的每个操作都是线程安全的,它也不会重复。

答案 3 :(得分:0)

您的商务逻辑(ProcessData)肯定存在问题。
也许不是pararell.foreach,但我认为这可能会加快您的代码速度,使用LINQ也是异步的。
就是这样,我正在处理某些数据上的并行异步操作。
您可能需要展平taskList(从head写入的完整伪代码)的结果。您始终可以始终使用yield return来实现稍后的列表,这可能会使它更加固定。但是请谨慎使用yield:)

var taskList = results.Select(async item =>
    {
        return await ProcessData(item, processedData);  
    });

await Task.WhenAll(taskList);

使用WhenAll或WaitAll取决于您要的大小写

  

Task.WaitAll:

At least one of the Task instances was canceled -or- an exception was thrown during the execution of  
at least one of the Task instances.If a task was canceled, the AggregateException contains an  
OperationCanceledException in its InnerExceptions collection.

Task.WhenAll:

If any of the supplied tasks completes in a faulted state, the returned task will also complete in a   
Faulted state, where its exceptions will contain the aggregation of the set of unwrapped exceptions  
from each of the supplied tasks.