Parallel.ForEachAsync中CancellationTokenSource的正确用法咨询
这段代码中CancellationTokenSource的使用存在问题
核心问题点
- 未关联外部传入的
cancellationToken:外部调用方发起取消时,内部并行循环不会响应,不符合异步操作的取消规范。 - 未将自定义
CancellationTokenSource的Token传入Parallel.ForEachAsync:调用cancellationTokenSource.Cancel()后,并行循环不会停止调度新任务,已启动的任务也无法感知取消信号。 - 未释放
CancellationTokenSource资源:未用using包裹,存在资源泄漏风险。 - 调用
_service.GetObject时未传递取消Token:即使触发取消,正在执行的异步操作也无法被中断。
修正后的代码
public async Task<Result> Handle(MyQuery request, CancellationToken cancellationToken) { // 关联外部取消信号,自动释放资源 using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); try { await Parallel.ForEachAsync(myList, cts.Token, async (objectId, token) => { // 将取消Token传入服务方法,支持中途中断异步操作 var result = await _service.GetObject(objectId, token); if (result.Any()) { cts.Cancel(); // 抛出取消异常,让Parallel.ForEachAsync快速终止所有任务 token.ThrowIfCancellationRequested(); } }); } catch (OperationCanceledException) { return Result.Fail("Error message."); } return Result.Ok(); }
修正说明
- 用
using包裹CancellationTokenSource,确保资源自动释放;通过CreateLinkedTokenSource关联外部取消信号,兼顾外部调用方和内部逻辑的取消需求。 - 将
cts.Token传入Parallel.ForEachAsync,触发取消后,循环会停止调度新任务,已启动的任务也能通过Token感知取消。 - 调用
_service.GetObject时传递取消Token,让异步操作可以在取消时被中断,避免无效等待。 - 触发取消后抛出
OperationCanceledException,让Parallel.ForEachAsync快速终止所有任务,而非等待已启动任务全部完成。
内容的提问来源于stack exchange,提问作者user7849697
相关产品推荐
相关产品推荐

