C# 我捕获的AggregateException没有我期望的异常
我正在使用任务并行库设置一系列任务,如下所示,但我得到了一个奇怪的异常处理经验,我不理解 我使用Parallel.ForEach并调用一个包含对以下方法的调用的操作。这个Parallel.ForEach被包装在一个try…catch(AggregateException)中,当一个异常发生时——就像它在一个并行分支中发生的那样——一个SchemaValidation异常,那么我希望在AggregateException中看到这一点 然而,我得到的是“一个任务被取消了”——TaskCanceledException。我的SchemaValidationException去哪了C# 我捕获的AggregateException没有我期望的异常,c#,.net,exception,task-parallel-library,C#,.net,Exception,Task Parallel Library,我正在使用任务并行库设置一系列任务,如下所示,但我得到了一个奇怪的异常处理经验,我不理解 我使用Parallel.ForEach并调用一个包含对以下方法的调用的操作。这个Parallel.ForEach被包装在一个try…catch(AggregateException)中,当一个异常发生时——就像它在一个并行分支中发生的那样——一个SchemaValidation异常,那么我希望在AggregateException中看到这一点 然而,我得到的是“一个任务被取消了”——TaskCanceled
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);
private static void ProcessChunk(任务选择任务,
i存储库,
IIIdentifiedExtractChunk identifiedExtractChunk,
IBatchRunConfiguration批运行配置,
IBatchRun批处理运行,
ILog日志,
IAAuthenticationCertificate authenticationCertificate,
IFileSystem文件系统,
长批处理(RUNRID)
{
var transformationTask=selectionTask.ContinueWith(TransformationFunction.Transformation(identifiedExtractChunk、batchRunConfiguration、batchRun),
TaskContinuationOptions。无故障);
var schemaValidationTask=transformationTask.ContinueWith(SchemaValidationFunction.schemaValidationTask(batchRunConfiguration),
TaskContinuationOptions。无故障);
var compressTask=schemaValidationTask.ContinueWith(CompressFunction.compressTask(identifiedExtractChunk),
TaskContinuationOptions。无故障);
var encryptTask=compressTask.ContinueWith(EncryptionFunction.encryptTask(authenticationCertificate)),
TaskContinuationOptions。无故障);
var fileGenerationTask=encryptask.ContinueWith(FileGenerationFunction.fileGenerationTask(identifiedExtractChunk、batchRunConfiguration、fileSystem),
TaskContinuationOptions。无故障);
//在我们开始处理之前花点时间
DateTime startBatchItemProcessing=DateTime.Now;
//从选择任务开始
selectionTask.Start();
//然后等待链中的最后一个任务
fileGenerationTask.Wait();
//在处理结束时花点时间
DateTime endBatchItemProcessing=DateTime.Now;
//记录所有相关信息并将其添加到集合中
IBatchChunkProcessed batchChunkProcessed=GetBatchItemProcessed(identifiedExtractChunk、batchRunRid、fileGenerationTask.Result、transformationTask.Result.Item2、startBatchItemProcessing、endBatchItemProcessing);
BatchItemsProcessed.Add(batchChunkProcessed);
让我们稍微简化一下您的代码:
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.cancelled
)。但这意味着t3
可以正常运行,如果它不抛出,t3.Wait()
不会抛出任何异常
如何解决此问题?首先,您可能不应该使用TaskContinuationOptions。不是有故障的
,而是TaskContinuationOptions。只使用OnOnOnToCompletion
。但这并不能解决“消失”异常的问题。要解决此问题,我看到了两种可能性:
Wait()
在每个继续的开头,不要使用任何任务继续选项
。这意味着您可能会在aggregateeexception
中包装一些异常,它本身包装在另一个aggregateeexception
中。要解决这个问题,您可以使用或。WaitAll()
将抛出一个aggregateeexception
,该异常将包含原始异常,并且对于由于第一个异常而取消的每个任务也将抛出TaskCanceledException
为什么在这里使用
Task
s?为什么不按顺序执行所有方法?代码似乎与问题无关。发布捕获并处理异常的代码。@svick-传入的选择任务是并行的。此外,这些是离散的构建块任务,可以很容易地重新执行sed-可能在其他上下文中执行根任务。@HansPassant-问题不在于异常处理代码-无论我把它放在哪里,我都遇到了同样的问题。我选择了task.WaitAll选项-似乎是最干净的。我现在得到了我想要的异常以及TaskCanceledExceptions。非常感谢。