4

我正在使用任务并行库来设置一系列任务,如下所示,但我得到了一种我不理解的奇怪异常处理体验。

我使用 Parallel.ForEach 并调用一个 Action,其中包括对以下方法的调用。此 Parallel.ForEach 包装在 try...catch(AggregateException) 中,当发生异常时 - 就像在其中一个 Parallel 分支中一样 - SchemaValidation 异常,然后我希望在 AggregateException 中看到它。

但是,我得到的是“任务被取消”-TaskCanceledException。我的 SchemaValidationException 去哪儿了?

        private static void ProcessChunk(Task<ISelectedChunk> selectionTask, 
                                     IRepository repository, 
                                     IIdentifiedExtractChunk identifiedExtractChunk, 
                                     IBatchRunConfiguration batchRunConfiguration, 
                                     IBatchRun batchRun, 
                                     ILog log, 
                                     IAuthenticationCertificate authenticationCertificate, 
                                     IFileSystem fileSystem,
                                     long batchRunRid)
    {
        var transformationTask = selectionTask.ContinueWith(TransformationFunction.Transformation(identifiedExtractChunk, batchRunConfiguration, batchRun),
                                                            TaskContinuationOptions.NotOnFaulted);

        var schemaValidationTask = transformationTask.ContinueWith(SchemaValidationFunction.SchemaValidationTask(batchRunConfiguration),
                                                                   TaskContinuationOptions.NotOnFaulted);

        var compressTask = schemaValidationTask.ContinueWith(CompressFunction.CompressTask(identifiedExtractChunk),
                                                             TaskContinuationOptions.NotOnFaulted);

        var encryptTask = compressTask.ContinueWith(EncryptionFunction.EncryptTask(authenticationCertificate),
                                                    TaskContinuationOptions.NotOnFaulted);

        var fileGenerationTask = encryptTask.ContinueWith(FileGenerationFunction.FileGenerationTask(identifiedExtractChunk, batchRunConfiguration, fileSystem),
                                                          TaskContinuationOptions.NotOnFaulted);
        // Take the time before we start the processing
        DateTime startBatchItemProcessing = DateTime.Now;

        // Start with the Selection Task
        selectionTask.Start();

        // And wait on the last task in the chain
        fileGenerationTask.Wait();

        // Take the time at the end of the processing
        DateTime endBatchItemProcessing = DateTime.Now;

        // Record all the relevant information and add it to the collection 
        IBatchChunkProcessed batchChunkProcessed = GetBatchItemProcessed(identifiedExtractChunk, batchRunRid, fileGenerationTask.Result, transformationTask.Result.Item2, startBatchItemProcessing, endBatchItemProcessing);
        BatchItemsProcessed.Add(batchChunkProcessed);
4

1 回答 1

6

让我们稍微简化一下您的代码:

var t1 = Task.Factory.StartNew(a1);
var t2 = t1.ContinueWith(a2, TaskContinuationOptions.NotOnFaulted);
var t3 = t2.ContinueWith(a3, TaskContinuationOptions.NotOnFaulted);

t3.Wait();

现在假设a1抛出异常。发生的情况是t1出现故障 ( t1.Status == TaskStatus.Faulted)。因此,t2无法运行(因为NotOnFaulted),因此将被取消。但这可能不是您所期望的:t2不会出错,它会被取消(t2.Status == TaskStatus.Canceled)。但这意味着它t3可以正常运行,并且如果它不抛出,t3.Wait()则不会抛出任何异常。

如何解决这个问题?首先,您可能不应该使用TaskContinuationOptions.NotOnFaulted,而是使用TaskContinuationOptions.OnlyOnRanToCompletion。但这并不能解决“消失”异常的问题。为了解决这个问题,我看到了两种可能性:

  1. 在每个延续开始时调用Wait(),不要使用任何TaskContinuationOptions. 这意味着您可能会收到一些包含在 中的异常AggregateException,该异常本身包含在 中AggregateException,而该异常又包含在另一个中AggregateException,等等。要解决此问题,您可以使用Flatten()or Handle()

  2. 等待所有任务,使用Task.WaitAll(). WaitAll()将抛出一个AggregateException包含原始异常以及TaskCanceledException由于第一个异常而被取消的每个任务的异常。

于 2012-04-04T13:24:42.110 回答