【问题标题】:The AggregateException I catch does not have the exception I expect我捕获的 AggregateException 没有我期望的异常
【发布时间】:2012-04-18 00:48:44
【问题描述】:

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

我使用 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);

【问题讨论】:

  • 你为什么还要在这里使用Tasks?为什么不按顺序执行所有方法?
  • 代码似乎与问题无关。贴出捕获并处理异常的代码。
  • @svick - 传入的选择任务是并行的。此外,这些是离散的构建块任务,可以很容易地在其他环境中重复使用 - 并可能成为根任务。
  • @HansPassant - 问题不在于异常处理代码 - 无论我把它放在哪里,我都遇到了同样的问题。

标签: c# .net exception task-parallel-library


【解决方案1】:

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

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()Handle()

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

【讨论】:

  • 我选择了 Task.WaitAll 选项 - 似乎是最干净的。我现在得到了我想要的异常以及 TaskCanceledExceptions。非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-11-16
  • 2012-01-22
  • 1970-01-01
  • 1970-01-01
  • 2020-11-16
相关资源
最近更新 更多