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

如何判断Task.Delay是正常完成还是被CancellationToken取消

问题核心

你遇到的情况是因为CancellationTokenSource(5000)的5秒超时和Task.Delay(5000)的等待时长完全同步——5秒后两者几乎同时触发,不管Delay是否正常跑完,Token的取消请求状态都会被置为true,自然没法靠这个属性直接区分结果。

以下是几种可行的判断方式:

方法1:用Task.WhenAny区分先完成的任务

把Delay任务和取消信号的等待任务分开,通过Task.WhenAny判断哪个先结束:

var cts = new CancellationTokenSource(5000);
// 不带取消令牌的Delay任务,确保它能正常跑完5秒
var delayTask = Task.Delay(5000);
// 绑定取消令牌的空等待任务,取消时会触发完成
var cancelTriggeredTask = Task.Delay(Timeout.Infinite, cts.Token);

var completedTask = await Task.WhenAny(delayTask, cancelTriggeredTask);

if (completedTask == delayTask)
{
    // Delay先完成,说明是正常等待满时长结束
    Console.WriteLine("等待满5秒完成");
}
else
{
    // 取消信号先触发,说明任务被取消
    Console.WriteLine("任务被取消");
}

原理:Task.WhenAny会返回最先完成的任务。如果Delay正常跑完,它会比取消触发的任务先完成(哪怕只差几毫秒);反之如果取消信号提前触发,取消任务会先结束。

方法2:捕获取消异常并结合时间判断

如果必须给Task.Delay绑定取消令牌,可以通过捕获OperationCanceledException,同时记录执行时长辅助判断:

var cts = new CancellationTokenSource(5000);
var startTime = DateTime.UtcNow;
bool isCompletedNormally = false;

try
{
    await Task.Delay(5000, cts.Token);
    // 能走到这里说明Delay正常完成,未被取消
    isCompletedNormally = true;
}
catch (OperationCanceledException)
{
    // 捕获到取消异常后,计算耗时判断是否接近5秒
    var elapsedMs = (DateTime.UtcNow - startTime).TotalMilliseconds;
    // 留100ms误差范围,避免系统计时精度导致误判
    isCompletedNormally = elapsedMs >= 4900;
}

if (isCompletedNormally)
{
    Console.WriteLine("等待满5秒完成");
}
else
{
    Console.WriteLine("任务被取消");
}

注意:这种方法依赖系统计时精度,适合对判断精度要求不高的场景。

方法3:拆分取消逻辑(推荐)

如果业务允许,尽量不要让CancellationTokenSource的超时时间和Task.Delay的时长完全一致,比如给一方调整时间差,这样就能通过是否抛出异常直接判断:

var cts = new CancellationTokenSource(5500); // 超时设为5.5秒
try
{
    await Task.Delay(5000, cts.Token);
    Console.WriteLine("等待满5秒完成");
}
catch (OperationCanceledException)
{
    Console.WriteLine("任务被取消");
}

这种方式最简洁:只要Delay正常跑完,cts还没触发取消,不会抛出异常;只有当Delay未跑完就触发取消时,才会抛出异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 13:24:58