You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用CancellationToken实现单个异步方法异常时取消全部异步任务

搞定多异步任务异常时批量取消的问题

嘿,我明白你的困扰——本来想着某个任务抛异常就取消所有任务,但令牌取消后其他任务却没停,对吧?核心问题其实是:CancellationToken的取消通知不是强制终止任务的,得让你的异步方法主动“听”到这个信号才行。

下面给你一步步拆解正确的实现思路和代码:

1. 先理清楚核心逻辑

别手动在每个任务的异常里去取消令牌,应该用CancellationTokenSource(简称CTS)来统一管理令牌。让所有异步任务共享同一个CancellationToken,一旦某个任务抛异常,我们就调用CTS的Cancel()方法,同时确保每个任务都能响应这个取消信号。

2. 完整可运行的示例代码

using System;
using System.Threading;
using System.Threading.Tasks;

namespace CancelationTest
{
    class Program
    {
        static async Task Main(string[] args)
        {
            // 用using管理CTS,确保资源能正确释放
            using var cts = new CancellationTokenSource();
            var cancelToken = cts.Token;

            // 把所有要执行的异步任务存到数组里,想扩展到100个直接加就行
            var allTasks = new[]
            {
                RunAsyncJob("任务A", 3000, cancelToken),
                RunAsyncJob("任务B", 5000, cancelToken)
            };

            try
            {
                // 等待所有任务完成,只要有一个抛异常,这里会立刻进入catch块
                await Task.WhenAll(allTasks);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"抓到异常啦:{ex.Message},马上取消所有任务!");
                // 触发全局取消信号
                cts.Cancel();
                // 可选:等所有任务完成取消流程,避免程序直接退出
                await Task.WhenAll(allTasks);
            }

            Console.WriteLine("所有任务都结束咯");
        }

        // 这个是支持取消的异步任务模板,你可以根据自己的业务改
        static async Task RunAsyncJob(string jobName, int delayMs, CancellationToken token)
        {
            try
            {
                Console.WriteLine($"{jobName} 开始执行");
                
                // 用带token的Task.Delay,它会自动检查取消信号
                await Task.Delay(delayMs, token);

                // 如果是你自己的业务逻辑,记得定期检查令牌状态
                if (token.IsCancellationRequested)
                {
                    // 抛出取消异常,标记这个任务为已取消状态
                    token.ThrowIfCancellationRequested();
                }

                Console.WriteLine($"{jobName} 顺利完成");
            }
            catch (OperationCanceledException)
            {
                Console.WriteLine($"{jobName} 被取消啦");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"{jobName} 出问题了:{ex.Message}");
                // 把异常抛出去,让上层的Task.WhenAll能捕获到,进而触发全局取消
                throw;
            }
        }
    }
}

3. 几个必须注意的关键点

  • 共享令牌源:所有任务必须用同一个CancellationToken,不然取消信号传不到其他任务那里。
  • 任务要主动响应取消:
    • 如果你用的是.NET自带的异步API(比如Task.Delay、HttpClient的请求方法),一定要把令牌传进去,这些API会自动检查取消信号并抛出异常终止任务。
    • 要是你写的是自定义业务逻辑,得自己定期检查token.IsCancellationRequested,必要时主动抛出OperationCanceledException来终止任务。
  • 异常要往上抛:任务里的异常别自己吞了,要重新抛出去,这样上层的Task.WhenAll才能捕获到,进而触发全局取消。
  • 用using管理CTS:避免资源泄漏,这个好习惯得保持。

4. 你之前踩坑的原因

大概率是这两个问题:

  • 你的异步方法内部根本没检查取消令牌,就算令牌被取消了,任务该跑还是继续跑。
  • 可能每个任务用的是不同的令牌源,导致取消信号只在单个任务里生效,其他任务收不到。

内容的提问来源于stack exchange,提问作者Raskolnikov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:33:58