如何修复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
相关产品推荐
相关产品推荐

