我对C#还不是很熟悉,今天开始尝试使用TPL。我决定写一个修改过的Task.WhenAll作为一个练习。我希望它具有以下行为:
在实际生产环境中我不会使用它,这只是为了测试我的基本功。我意识到更简单的方法是进行Task.WhenAll,并使列表中的任务本身具有在失败时执行取消的连续性。
- 发现第一个失败或被取消的任务时,取消其余任务而不是等待它们完成。
- 如果任务失败,则返回的任务应设置正确的异常(即不通过继续运行并替换为OperationCancelledException())
- 方法签名中没有异步关键字(想避免将其传递上去)。
在实际生产环境中我不会使用它,这只是为了测试我的基本功。我意识到更简单的方法是进行Task.WhenAll,并使列表中的任务本身具有在失败时执行取消的连续性。
public static Task WhenAllError(List<Task> tasks, CancellationToken ct)
{
var tcs = new TaskCompletionSource<object>();
return Task.WhenAny(tasks).ContinueWith<Task>((t) =>
{
if (tasks.Count == 0)
{
tcs.SetResult(null);
return tcs.Task;
}
if (t.IsFaulted)
{
Console.WriteLine("Task faulted. Cancelling other tasks: {0}", t.Id);
cts.Cancel();
// Make sure the tasks are cancelled if necessary
tcs.SetException(t.Exception);
return tcs.Task;
}
// Similarly handle Cancelled
tasks.Remove(t);
return WhenAllError(tasks, ct);
}).Unwrap();
}