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

如何修复Task.Run的取消行为不一致问题?

修复Task.Run异步委托与同步委托的取消行为不一致问题

Task.Run方法提供了接受同步和异步委托的重载:

public static Task Run (Action action);
public static Task Run (Func<Task> function);

但这两个重载在委托抛出OperationCanceledException时行为不一致:同步委托会让任务处于Faulted状态,而异步委托会让任务处于Canceled状态。以下是最小复现代码:

CancellationToken token = new(canceled: true);

Task taskSync = Task.Run(() => token.ThrowIfCancellationRequested());
Task taskAsync = Task.Run(async () => token.ThrowIfCancellationRequested());
    
try { Task.WaitAll(taskSync, taskAsync); } catch { }
    
Console.WriteLine($"taskSync.Status: {taskSync.Status}"); // Faulted
Console.WriteLine($"taskAsync.Status: {taskAsync.Status}"); // Canceled (不符合预期)

输出结果:

taskSync.Status: Faulted
taskAsync.Status: Canceled

我们需要实现一个Task.Run的变体方法TaskRun2,让它的行为和接受同步委托的Task.Run保持一致:当委托抛出OperationCanceledException时,任务默认以Faulted状态异步完成;只有当传入的cancellationToken参数与异常中存储的token匹配时,任务才处于Canceled状态。

方法签名如下:

public static Task TaskRun2 (Func<Task> action,
    CancellationToken cancellationToken = default);

以下是该方法的期望行为示例:

CancellationToken token = new(canceled: true);

Task taskA = TaskRun2(async () => token.ThrowIfCancellationRequested());
Task taskB = TaskRun2(async () => token.ThrowIfCancellationRequested(), token);
    
try { Task.WaitAll(taskA, taskB); } catch { }
    
Console.WriteLine($"taskA.Status: {taskA.Status}");
Console.WriteLine($"taskB.Status: {taskB.Status}");

期望输出:

taskA.Status: Faulted
taskB.Status: Canceled

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 08:50:19