.NET 6的Parallel.ForEachAsync为何需要两个取消令牌参数?
Parallel.ForEachAsync 双取消令牌的作用与差异
两个令牌的各自作用
- 方法入参位置的
CancellationToken(你代码里的token变量):属于全局循环控制令牌
它的作用范围覆盖整个并行循环的全生命周期:- 循环启动前如果该令牌已经被标记为取消,
Parallel.ForEachAsync会直接抛出OperationCanceledException,不会启动任何迭代任务 - 循环运行过程中该令牌被取消时,会立即终止后续未分配的迭代调度,同时通知所有正在运行的迭代需要终止
- 循环启动前如果该令牌已经被标记为取消,
- 委托入参位置的
CancellationToken(你代码里的t变量):属于迭代关联令牌
这个令牌是Parallel.ForEachAsync内部生成的,和当前迭代的生命周期绑定,它的取消触发条件包含两种场景:- 你传入的全局循环控制令牌被取消
- 任意一个迭代抛出未处理的异常,触发并行循环的整体终止流程
二者的核心差异
二者最值得注意的差异是取消触发场景的覆盖范围不同:
- 全局控制令牌只会响应你主动调用
cts.Cancel()的操作,如果并行循环是因为某个迭代抛出异常触发终止,全局令牌的IsCancellationRequested属性仍然为false,但委托内的迭代令牌会被标记为取消- 迭代内做取消状态检查时,优先使用委托传入的迭代令牌,不要只依赖自己定义的全局令牌,否则会漏掉异常触发的终止信号,导致迭代任务无法及时退出
示例代码说明
你提供的示例逻辑可以正常终止循环,仅存在一个冗余点:循环外的token.ThrowIfCancellationRequested()可以直接删除,Parallel.ForEachAsync本身会在启动前自动检查你传入的全局令牌状态,不需要手动调用检查。
内容的提问来源于stack exchange,提问作者Vic F
相关产品推荐
相关产品推荐

