如果我await Task.WhenAll(tasks)
,如果一个或多个任务失败,则抛出异常。我想手动检查每个任务对象。
catch(Exception)
通常不是一个好主意。在这种情况下这样做是否合理?或许还有另一种方法可以等待所有任务?我无法抓住AggregateException
,因为如果只有一个,它将被解开。
如何在异步方法中正确执行?
答案 0 :(得分:0)
因此,如果您的一个或多个任务可能遇到问题,您希望其他任务继续完成
public async Task WaitAllEvenIfException(this Task[] tasksToWaitFor)
{
// wait until all completed, even if one of them raises exception
While (!tasksToWaitFor.All(task => task.IsCompleted)
{
// not all completed yet
try
{
await Task.WhenAll(tasksToWaitFor);
}
catch (AggregateException exc)
{
// one or more of the Tasks threw exception,
// don't handle now, wait until all Completed
}
}
}
用法:
Task[] tasksToWaitFor = ...
await this.WaitAllEvenIfException(tasksToWaitFor);
// now all completed, you can use the State to check which ones threw exception
IEnumerable<Task> tasksThatThrewExeption = tasksToWaitFor
.Where(task => task.Status == TaskStatus.Faulted);
foreach (Task exceptedTask in tasksThatThrewException)
{
Exception exc = exceptedTask.Exception;
// handle exception
}
答案 1 :(得分:-1)
下面的AwaitCompletion
扩展方法可以使用更通用的API来满足您的需求。它会返回Task
,因此您仍然必须通过await
或Task.Wait()
或其他方式等待。
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
public static class TaskExtensions
{
public static Task AwaitCompletion<T>(this ICollection<Task<T>> unfinishedTasks)
{
int remainingCount = unfinishedTasks.Count;
var promise = new TaskCompletionSource<ICollection<Task<T>>>();
var finishers = unfinishedTasks.Select(x => x.ContinueWith((task, state) =>
{
int postCount = Interlocked.Decrement(ref remainingCount);
if (postCount == 0)
{
promise.SetResult(unfinishedTasks);
}
}, remainingCount));
// force evaluation
var _ = finishers.ToList();
return promise.Task;
}
/// <summary>
/// Unlike Task.Value, this doesn't wait for completion. Hence, it also doesn't
/// throw exceptions.
/// </summary>
/// <returns>Value if completed, otherwise null (or default value if a value type)</returns>
public static T GetResultOrDefault<T>(this Task<T> self)
{
if (self.IsCompletedSuccessfully)
{
return self.Result;
}
else
{
return default(T);
}
}
}
在完成返回的Task
值之后,unfinishedTasks
中的所有任务都将完成或出错(或者,如果您将Task.Wait()
用于超时,则仍将继续)。 AwaitCompletion
不会引发异常,等待它只会在达到超时时引发异常。要检索异常,请查看您传递的任务。
用法:
Task[] tasksToWaitFor = ...
await tasksToWaitFor.AwaitCompletion()
foreach (var task in tasksToWaitFor)
{
Console.WriteLine("result: {}", task.GetResultOrDefault());
}
GetResultOrDefault
扩展方法很重要。如果您直接点击Value
,则在任务失败时它将抛出AggregateException,OTOH GetResultOrDefault
将返回null。
答案 2 :(得分:-2)
用
暂时吞下异常await Task.WhenAll(tasks).ContinueWith(delegate {} )
但请记住,然后单独检查所有任务并正确显示错误。