异步任务中通过CancellationToken实现按键终止foreach循环的方案
问题根因与修复方案
你遇到的延迟生效问题是因为CancellationToken的状态检测逻辑仅放在了foreach循环的外层,只有当一轮完整的foreach遍历完所有stations元素后才会执行取消判断,自然无法在迭代过程中触发终止。
修正后代码
var ts = new CancellationTokenSource(); CancellationToken ct = ts.Token; // 启动业务执行任务 Task.Run(async () => { while (!ct.IsCancellationRequested) { foreach (var station in stations) { // 每次迭代前先检测取消请求 if (ct.IsCancellationRequested) { Console.WriteLine("task canceled"); break; } Console.WriteLine(station.name + " "); // 用支持取消的异步延时替换Thread.Sleep,延时期间也能响应取消 await Task.Delay(100, ct); } if (!ct.IsCancellationRequested) { await Task.Delay(100, ct); } } }, ct); // 监听按键输入,按下任意键触发取消 Console.ReadKey(); ts.Cancel(); Console.ReadLine();
核心改动说明
- 将取消状态检测移入
foreach循环内部,每次处理单个station前都校验取消信号,收到请求后立刻终止迭代 - 替换
Thread.Sleep为带CancellationToken参数的Task.Delay,延时等待期间收到取消请求会立即中断,无需等计时结束,取消响应更及时 - 修复了原代码中启动就直接调用
ts.Cancel()的逻辑,改为监听按键输入后再触发取消,匹配你按下按键终止循环的需求
如果希望符合TPL的标准取消范式,也可以直接调用ct.ThrowIfCancellationRequested()替代手动判断跳出,此时只需在任务外层捕获OperationCanceledException即可完成取消逻辑处理。
内容的提问来源于stack exchange,提问作者Roberto Rizzi
相关产品推荐
相关产品推荐

