0

0

c# CancellationTokenSource.CancelAfter 的用法和计时器精度

月夜之吻

月夜之吻

发布时间:2026-01-14 19:35:02

|

848人浏览过

|

来源于php中文网

原创

CancelAfter 本质是基于 System.Threading.Timer 的延迟取消机制,无法保证毫秒级精度,适用于“最多等待N秒”场景而非精确计时。

c# cancellationtokensource.cancelafter 的用法和计时器精度

CancelAfter 本质是基于 Timer 实现的延迟取消

CancelAfter 并不是启动一个高精度计时器,而是内部调用 System.Threading.Timer,以指定毫秒数为间隔触发一次 Cancel()。这意味着它的触发时机受 .NET 线程池调度、系统时钟粒度和 GC 暂停影响,**无法保证精确到毫秒级**。

典型场景是“最多等待 3 秒,超时就放弃”,而不是“必须在第 3000 毫秒整点取消”。如果你看到实际取消发生在 3012ms 或 3040ms,这是正常行为。

  • Windows 默认系统时钟分辨率约 15.6ms(可通过 timeBeginPeriod(1) 提升,但不推荐在普通应用中使用)
  • .NET 6+ 在部分平台(如 Linux with epoll)对 Timer 做了优化,但 CancelAfter 仍不提供 sub-millisecond 保证
  • 频繁创建短时 CancelAfter(1) 不仅无效,还会增加线程池压力和 GC 负担

CancelAfter 和手动 Timer 的行为差异

直接用 System.Threading.Timer 可以控制回调线程上下文、复用实例、甚至尝试补偿误差;而 CancelAfter 是一次性、黑盒封装,调用后无法获取底层 Timer 实例,也无法重置或查询剩余时间。

例如,你不能像这样“续期”:

cts.CancelAfter(2000);
// ❌ 下面这行不会延长原定时器,而是新建一个,旧的仍会在 ~2s 后触发
cts.CancelAfter(5000);

如果需要动态调整超时,应改用 Timer 手动管理,或每次取消旧的再新建新的 CancellationTokenSource

  • CancelAfter 调用后,若 cts.Token.IsCancellationRequested 已为 true,新定时器会被静默忽略
  • 重复调用 CancelAfter 会丢弃前一个定时器(内部调用 Change(Timeout.Infinite, Timeout.Infinite)),但存在极小窗口期可能触发两次取消(罕见,仅当前次回调已入队但尚未执行)
  • 它不参与 SynchronizationContext,回调总在线程池线程上执行

常见误用:把 CancelAfter 当作 Sleep 或轮询替代品

有人试图用 cts.CancelAfter(100); Thread.Sleep(100); 来“等待 100ms 或提前取消”,这是危险的——CancelAfter 不阻塞,Thread.Sleep 也不响应 token,两者完全解耦。

ShopWind网店系统
ShopWind网店系统

ShopWind网店系统是国内最专业的网店程序之一,采用ASP语言设计开发,速度快、性能好、安全性高。ShopWind网店购物系统提供性化的后台管理界面,标准的网上商店管理模式和强大的网店软件后台管理功能。ShopWind网店系统提供了灵活强大的模板机制,内置多套免费精美模板,同时可在后台任意更换,让您即刻快速建立不同的网店外观。同时您可以对网模板自定义设计,建立个性化网店形象。ShopWind网

下载

正确做法是配合可取消的等待操作,例如:

var cts = new CancellationTokenSource();
cts.CancelAfter(100);
await Task.Delay(1000, cts.Token); // 真正响应取消

或者用于 I/O 操作:

using var httpClient = new HttpClient();
var cts = new CancellationTokenSource();
cts.CancelAfter(5000);
await httpClient.GetAsync("https://api.example.com", cts.Token);
  • 不要在同步上下文中依赖 CancelAfter 实现“定时检查”逻辑;它不提供回调通知,也不返回句柄
  • 不要用它替代 Task.Run(() => { Thread.Sleep(100); }).Wait(cts.Token) —— 这种写法既低效又无法真正中断 Thread.Sleep
  • 在 ASP.NET Core 中,HttpContext.RequestAborted 已自带请求级取消,一般无需额外套一层 CancelAfter

精度不够时的实际应对策略

如果你的业务确实对延迟敏感(比如实时音视频帧同步、高频交易准备阶段),CancelAfter 就不该出现在关键路径上。此时应切换方案:

  • Stopwatch + 循环轮询 token.IsCancellationRequested(适合短时、CPU 可接受占用)
  • 使用 IOCP-base 的异步原语(如 Socket.AwaitableSocketAsyncEventArgs 配合自定义超时)
  • 在 Windows 上考虑 WaitHandle.WaitAny 组合 cts.Token.WaitHandlenew AutoResetEvent() + Set() 定时触发(需另启线程或 Timer
  • 第三方库如 System.Threading.ChannelsReader.WaitToReadAsync(cts.Token) 内部做了更精细的超时处理,可间接利用

多数 Web API 调用、数据库查询、文件读写场景中,±20ms 的偏差完全可接受,CancelAfter 仍是简洁安全的选择——前提是别把它当成精密仪器来用。

相关专题

更多
登录token无效
登录token无效

登录token无效解决方法:1、检查token的有效期限,如果token已经过期,需要重新获取一个新的token;2、检查token的签名,如果签名不正确,需要重新获取一个新的token;3、检查密钥的正确性,如果密钥不正确,需要重新获取一个新的token;4、使用HTTPS协议传输token,建议使用HTTPS协议进行传输 ;5、使用双因素认证,双因素认证可以提高账户的安全性。

6083

2023.09.14

登录token无效怎么办
登录token无效怎么办

登录token无效的解决办法有检查Token是否过期、检查Token是否正确、检查Token是否被篡改、检查Token是否与用户匹配、清除缓存或Cookie、检查网络连接和服务器状态、重新登录或请求新的Token、联系技术支持或开发人员等。本专题为大家提供token相关的文章、下载、课程内容,供大家免费下载体验。

801

2023.09.14

token怎么获取
token怎么获取

获取token值的方法:1、小程序调用“wx.login()”获取 临时登录凭证code,并回传到开发者服务器;2、开发者服务器以code换取,用户唯一标识openid和会话密钥“session_key”。想了解更详细的内容,可以阅读本专题下面的文章。

1058

2023.12.21

token什么意思
token什么意思

token是一种用于表示用户权限、记录交易信息、支付虚拟货币的数字货币。可以用来在特定的网络上进行交易,用来购买或出售特定的虚拟货币,也可以用来支付特定的服务费用。想了解更多token什么意思的相关内容可以访问本专题下面的文章。

1215

2024.03.01

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

480

2023.08.10

Java 并发编程高级实践
Java 并发编程高级实践

本专题深入讲解 Java 在高并发开发中的核心技术,涵盖线程模型、Thread 与 Runnable、Lock 与 synchronized、原子类、并发容器、线程池(Executor 框架)、阻塞队列、并发工具类(CountDownLatch、Semaphore)、以及高并发系统设计中的关键策略。通过实战案例帮助学习者全面掌握构建高性能并发应用的工程能力。

60

2025.12.01

windows查看端口占用情况
windows查看端口占用情况

Windows端口可以认为是计算机与外界通讯交流的出入口。逻辑意义上的端口一般是指TCP/IP协议中的端口,端口号的范围从0到65535,比如用于浏览网页服务的80端口,用于FTP服务的21端口等等。怎么查看windows端口占用情况呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

576

2023.07.26

查看端口占用情况windows
查看端口占用情况windows

端口占用是指与端口关联的软件占用端口而使得其他应用程序无法使用这些端口,端口占用问题是计算机系统编程领域的一个常见问题,端口占用的根本原因可能是操作系统的一些错误,服务器也可能会出现端口占用问题。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

1098

2023.07.27

Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

36

2026.01.14

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 7.1万人学习

Git 教程
Git 教程

共21课时 | 2.7万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号