一个任务失败时,是否可以从Task.WhenAll获得成功的结果?

编程入门 行业动态 更新时间:2024-10-21 20:32:58
本文介绍了一个任务失败时,是否可以从Task.WhenAll获得成功的结果?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

给出以下内容:

var tPass1 = Task.FromResult(1); var tFail1 = Task.FromException<int>(new ArgumentException("fail1")); var tFail2 = Task.FromException<int>(new ArgumentException("fail2")); var task = Task.WhenAll(tPass1, tFail1, tFail2); task.Wait();

对task.Wait()的调用将抛出一个AggregateException,其内部异常包含fail1和fail2异常.但是如何获得tPass1成功的结果?

the call to task.Wait() throws an AggregateException, whose inner exceptions contain the fail1 and fail2 exceptions. But how can I access the tPass1 successful result?

这可能吗?

我知道在WhenAll完成之后我可以通过tPass1.Result从单个任务中获得结果,但是有一种方法可以将它们放入数组中,从而不必手动跟踪所有进给的东西进入WhenAll?

I'm aware that I can get the result from the individual task after the WhenAll has finished, via tPass1.Result however is there a way to get them in an array to avoid having to manually track all the things feeding into the WhenAll?

推荐答案

任务失败时,我们将无法访问其 Result 属性,因为它会抛出.因此,要获得部分成功完成的WhenAll任务的结果,我们必须确保该任务将成功完成.然后,问题就变成了如何处理失败的内部任务.吞下它们可能不是一个好主意.至少我们要记录它们.这是一个替代性WhenAll的实现,该替代性不会抛出任何异常,但是会在 ValueTuple 结构.

When a task fails we cannot access its Result property because it throws. So to have the results of a partially successful WhenAll task, we must ensure that the task will complete successfully. The problem then becomes what to do with the exceptions of the failed internal tasks. Swallowing them is probably not a good idea. At least we would like to log them. Here is an implementation of an alternative WhenAll that never throws, but returns both the results and the exceptions in a ValueTuple struct.

public static Task<(T[] Results, Exception[] Exceptions)> WhenAllEx<T>(params Task<T>[] tasks) { return Task.WhenAll(tasks).ContinueWith(_ => // return a continuation of WhenAll { var results = tasks .Where(t => t.Status == TaskStatus.RanToCompletion) .Select(t => t.Result) .ToArray(); var aggregateExceptions = tasks .Where(t => t.IsFaulted) .Select(t => t.Exception) // The Exception is of type AggregateException .ToArray(); var exceptions = new AggregateException(aggregateExceptions).Flatten() .InnerExceptions.ToArray(); // Trick to flatten the hierarchy of AggregateExceptions return (results, exceptions); }, TaskContinuationOptions.ExecuteSynchronously); }

用法示例:

var tPass1 = Task.FromResult(1); var tFail1 = Task.FromException<int>(new ArgumentException("fail1")); var tFail2 = Task.FromException<int>(new ArgumentException("fail2")); var task = WhenAllEx(tPass1, tFail1, tFail2); task.Wait(); Console.WriteLine($"Status: {task.Status}"); Console.WriteLine($"Results: {String.Join(", ", task.Result.Results)}"); Console.WriteLine($"Exceptions: {String.Join(", ", task.Result.Exceptions.Select(ex => ex.Message))}");

输出:

状态:RanToCompletion 结果:1 例外:fail1,fail2

Status: RanToCompletion Results: 1 Exceptions: fail1, fail2

警告:上面的实现会忽略已取消的任务,因此不会模仿 Task.WhenAll :

Caution: the implementation above ignores canceled tasks, and so does not mimic the default behavior of Task.WhenAll:

如果提供的任务均未故障,但至少其中一项被取消,则返回的任务将以Canceled状态结束.

在这种情况下,更一致的行为是返回单个TaskCanceledException.可以通过在WhenAllEx内的最后return命令之前添加以下代码来完成此操作:

A more consistent behavior would be to return a single TaskCanceledException in this case. This can be done by adding this code inside the WhenAllEx, just before the final return command:

if (exceptions.Length == 0) { var canceledTask = tasks.FirstOrDefault(t => t.IsCanceled); if (canceledTask != null) { exceptions = new[] { new TaskCanceledException(canceledTask) }; } }

更多推荐

一个任务失败时,是否可以从Task.WhenAll获得成功的结果?

本文发布于:2023-11-12 20:26:09,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1582452.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:获得成功   Task   WhenAll

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!