首页 > 解决方案 > Parallel.ForEach 失败并显示“对象引用未设置为对象的实例”。例外

问题描述

非常简单Parallel.ForEach的调用有时会失败

你调用的对象是空的。

图书馆某处而不是我的代码中的异常。这是堆栈跟踪。

  at System.Threading.Tasks.TaskReplicator.Run[TState](ReplicatableUserAction`1 action, ParallelOptions options, Boolean stopOnFirstFailure)
   at System.Threading.Tasks.Parallel.PartitionerForEachWorker[TSource,TLocal](Partitioner`1 source, ParallelOptions parallelOptions, Action`1 simpleBody, Action`2 bodyWithState, Action`3 bodyWithStateAndIndex, Func`4 bodyWithStateAndLocal, Func`5 bodyWithEverything, Func`1 localInit, Action`1 localFinally)
--- End of stack trace from previous location where exception was thrown ---
   at System.Threading.Tasks.Parallel.ThrowSingleCancellationExceptionOrOtherException(ICollection exceptions, CancellationToken cancelToken, Exception otherException)
   at System.Threading.Tasks.Parallel.PartitionerForEachWorker[TSource,TLocal](Partitioner`1 source, ParallelOptions parallelOptions, Action`1 simpleBody, Action`2 bodyWithState, Action`3 bodyWithStateAndIndex, Func`4 bodyWithStateAndLocal, Func`5 bodyWithEverything, Func`1 localInit, Action`1 localFinally)
   at System.Threading.Tasks.Parallel.ForEachWorker[TSource,TLocal](IEnumerable`1 source, ParallelOptions parallelOptions, Action`1 body, Action`2 bodyWithState, Action`3 bodyWithStateAndIndex, Func`4 bodyWithStateAndLocal, Func`5 bodyWithEverything, Func`1 localInit, Action`1 localFinally)
   at System.Threading.Tasks.Parallel.ForEach[TSource](IEnumerable`1 source, Action`1 body)
...

它很少发生,我在 Linux 上的 .NET Core 2.1 应用程序上只看到过几次,没有明显的原因,也无法重现。

这是我的简化代码:

var chunkSize = 100;
var processingList = new List<int>();

// removed code here which fill the processing list with data. No nulls here for sure

Parallel.ForEach(
    ChunkIndexes(processingList.Count, chunkSize),
    (interval) =>
    {
        var worker = new MyWorker();
        worker.Process(processingList, interval.startIndex, interval.endIndex);
    });
// Function called by Parallel.ForEach()
public static IEnumerable<(int startIndex, int endIndex)> ChunkIndexes(int totalCount, int chunkSize)
{
    for (var i = 0; i < totalCount; i += chunkSize)
    {
        yield return (i, Math.Min(i + chunkSize, totalCount));
    }
}

中的代码Parallel.ForEach正在处理列表的不同部分,并且仅修改值但不以任何方式更改列表大小。没有异步/等待代码,没有文件访问,也没有网络调用。它看起来很简单,我只是无法弄清楚它是如何因任何原因而失败的。有任何想法吗?

标签: c#multithreading.net-coretask-parallel-library

解决方案


基于我自己代码中 Parallel.ForEach 的其他用途、失败堆栈跟踪和下面的评论,我做了一个小的代码更改。到目前为止一切看起来都不错。

基于您的 StackTrace 和 TaskReplicator.Run 的源代码,选项为 null 或复制器的 _pendigReplicas – Peter Csala 8 月 27 日 14:48

以下是在极少数情况下可能会失败的原始源代码:

Parallel.ForEach(
    ChunkIndexes(processingList.Count, chunkSize),
    (interval) => {... code here ... });

修改后的代码。仅添加了 ParallelOptions 参数:

Parallel.ForEach(
    ChunkIndexes(processingList.Count, chunkSize),
    new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount },
    (interval) => {... code here ... });

原始问题仅在 Linux 上运行使用 .net core 2.1 编译的 C# 代码时观察到。


推荐阅读