c# - 如果引发任何异常,如何在 Task.WhenAll 上取消并引发异常?

标签 c# async-await task-parallel-library task

我正在使用 Task.WhenAll 等待多项任务。当其中一个生成异常时,我希望 Task.WhenAll(或等待多个任务的任何其他方式)立即取消其他任务并引发异常。

这可能吗?

提前致谢

最佳答案

Cancellation is coopertive WhenAll 无法取消线程,但您可以向所有线程传递一个 CancellationToken 并在遇到异常时触发 token 。

CancellationTokenSource cts = new CancellationTokenSource();

var task1 = Func1Async(cts.Token);
task1.ContinueWith(task => cts.Cancel(), cts.Token, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
var task2 = Func2Async(cts.Token);
task2.ContinueWith(task => cts.Cancel(), cts.Token, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
var task3 = Func3Async(cts.Token);
task3.ContinueWith(task => cts.Cancel(), cts.Token, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);

await Task.WhenAll(task1, task2, task3);

在方法内部,您需要将 token.ThrowIfCancellationRequested() 放入函数内部以检查 token 并取消任务

public async Task Func1Async(CancellationToken token)
{
    foreach(var item in GetItems1())
    {
         await item.ProcessAsync(token);
         token.ThrowIfCancellationRequested();
    }
}

注意:您可以通过制作扩展方法来清理代码

public static class ExtensionMethods
{
    public static Task CancelOnFaulted(this Task task, CancellationTokenSource cts)
    {
        task.ContinueWith(task => cts.Cancel(), cts.Token, taskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
        return task;
    }

    public static Task<T> CancelOnFaulted<T>(this Task<T> task, CancellationTokenSource cts)
    {
        task.ContinueWith(task => cts.Cancel(), cts.Token, taskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
        return task;
    }
}

这会让代码看起来像

CancellationTokenSource cts = new CancellationTokenSource();

var task1 = Func1Async(cts.Token).CancelOnFaulted(cts);
var task2 = Func2Async(cts.Token).CancelOnFaulted(cts);
var task3 = Func3Async(cts.Token).CancelOnFaulted(cts);

await Task.WhenAll(task1, task2, task3);

关于c# - 如果引发任何异常,如何在 Task.WhenAll 上取消并引发异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41899842/

相关文章:

c# - Task.Yield() 与 Task.Delay(0)

c# - 使用 HttpPostedFileBase 的 ICollection 上传多个文件?

c# - 从后面的代码中检索 javascript var 值

c# - 创建同步请求的 .net 异步包装器

javascript - 为什么我的无限循环在异步函数中时会阻塞?

c# - 异步 Web 服务调用不一致异步

c# - 保证相同版本的 nuget 包

c# - 如何配置 log4net 以便可以将对象的属性映射到日志输出?

c# - 我可以克隆一个 IQueryable 以在另一个 DbContext 的 DbSet 上运行吗?

c# - 从 Task.Run 中抛出异常显示 "Not Handled from User Code"消息