C++ 实现高性能时间轮任务调度器及其解决海量高并发定时器瓶颈【源码】

雨雪酱_7241

雨雪酱_7241

2026-05-23

988人浏览

原创

std::chrono+std::thread无法支撑百万级定时器,因线程开销大或轮询精度低;时间轮以空间换时间,o(1)插入与到期处理,需分层设计、无锁队列、原子环形缓冲区、句柄生命周期管理及cpu核绑定。

c++ 实现高性能时间轮任务调度器及其解决海量高并发定时器瓶颈【源码】

为什么 std::chrono + std::thread 无法扛住百万级定时器

因为每个定时器都用 std::thread 或甚至 std::async 拉起一个等待线程,内存和上下文切换开销会指数级增长;而用 std::this_thread::sleep_until 轮询单线程,又无法做到亚毫秒精度且 CPU 占用飙升。真正瓶颈不在“怎么触发”,而在“怎么组织海量到期事件”。

时间轮(Timing Wheel)本质是空间换时间:把未来一段时间切分成固定槽(slot),每个槽挂一个任务链表,指针匀速拨动,只检查当前槽的任务——O(1) 插入、均摊 O(1) 到期处理,内存占用与活跃定时器数无关,只与时间跨度和精度有关。

实操建议:

  • 避免用 std::map<time_point task></time_point> 或 std::priority_queue 做调度核心,它们插入/删除都是 O(log n),n=100w 时单次操作已超 20μs,无法满足高频调度
  • 一级时间轮适合 0–60s、精度 10ms 的场景;若需支持 24h 后触发,必须分层(如:毫秒轮 + 秒轮 + 分轮),否则数组过大或溢出
  • 务必用无锁队列(如 moodycamel::ConcurrentQueue)承接从时间轮中摘出的待执行任务,防止 tick 线程被业务回调阻塞

如何用 std::atomic + ring buffer 实现无锁 tick 推进

时间轮的“指针”不能用普通变量加锁更新——高并发下 ++cur_slot 会成为热点。正确做法是让 tick 线程独占推进,用 std::atomic_uint32_t 存当前槽索引,所有添加定时器的线程只读不写。

关键点在于环形缓冲区(ring buffer)的边界判断:槽总数为 N,当前 tick 是 tick_idx,则一个定时器在 delay_ms = 500 后触发,应放入槽位 (tick_idx + delay_ms / resolution_ms) % N。注意整数除法截断误差,实际要向上取整。

示例(精度 10ms,总长 6000 槽 → 覆盖 60s):

uint32_t resolution_ms = 10;
uint32_t wheel_size = 6000;
uint32_t target_slot = (cur_tick.load() + (delay_ms + resolution_ms - 1) / resolution_ms) % wheel_size;

常见错误:

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载
  • 直接用 delay_ms / resolution_ms 导致 13ms 定时器被算成 1 槽(即 10ms),提前到期
  • 未对 target_slot 做 % wheel_size,delay 过大时数组越界
  • 在 tick 线程里直接调用用户回调——一旦某个回调卡住 100ms,整个轮子就停摆

定时器对象生命周期怎么不出 dangling pointer

C++ 里最危险的不是性能,是 shared_ptr<timer></timer> 被析构后,时间轮槽里还存着野指针。不能依赖引用计数自动清理:任务可能在轮子里挂了 10 分钟,而创建它的作用域早已退出。

正确做法是分离“注册”和“持有”:用户拿到的是轻量句柄(如 uint64_t timer_id),底层用 std::vector<:unique_ptr>></:unique_ptr> 管理真实对象,id 是 vector 下标 + 版本号(防复用冲突)。取消定时器时,仅原子标记该 slot 中对应节点为 cancelled,tick 线程摘链时跳过即可。

实操要点:

  • 不要在 Timer 析构函数里尝试从时间轮中移除自己——此时轮子可能正在遍历该槽
  • 用 std::atomic_flag 替代 bool 成员做 cancel 标记,确保多线程读写安全
  • 如果支持重复定时器(repeating),必须在每次触发后重新计算下一次槽位并插入,不能原地修改——插入过程非原子,可能被其他线程观察到中间态

Linux 上怎么把 tick 线程绑定到隔离 CPU 核并禁用频率调节

即使算法最优,若 tick 线程被调度器频繁迁移或 CPU 频率动态降频,10ms 精度也会漂移到 15ms 以上。这不是代码问题,是 OS 层面干扰。

必须做三件事:

  • 启动时用 sched_setaffinity 将 tick 线程绑死到某个 CPU 核(如 core 3),并设为 SCHED_FIFO 实时策略
  • 关闭该核的 CPUFreq:写 /sys/devices/system/cpu/cpu3/cpufreq/scaling_governor 为 performance
  • echo 1 > /proc/sys/kernel/preempt

否则,你看到的 “平均延迟 8.2ms” 很可能是统计均值,而 P99 延迟卡在 47ms——因为某次 tick 正好撞上内核软中断或页回收。

这步常被忽略:算法再漂亮,跑在不可控的调度环境里,就是纸上谈兵。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关专题

更多
c++和c语言的区别有哪些
c++和c语言的区别有哪些

c++和c语言的区别:1、面向对象编程(OOP)支持不同;2、新增特性不同;3、标准库不同;4、编译方式不同;5、命名空间不同等等。想了解更多c++的相关内容,可以阅读本专题下面的文章。

2024.03.14

2248

9

c++和python学习顺序推荐
c++和python学习顺序推荐

一般建议先学习C++,再学习Python,因为这样可以逐步从较为底层的编程语言向更高级的语言过渡。想了解更多python的相关内容,可以阅读本专题下面的文章。

2024.03.14

1019

6

python和c++学习性价比分析
python和c++学习性价比分析

Python易于学习,广泛应用于Web开发、数据科学和人工智能等领域,但性能较低。C语言性能高,适用于对性能要求较高的场景,如游戏开发和系统编程,但学习曲线陡峭,错误处理复杂。想了解更多python的相关内容,可以阅读本专题下面的文章。

2024.03.14

447

5

c语言和c++一样吗
c语言和c++一样吗

c语言和c++是两种不同的编程语言,虽然有相似之处,但存在显著差异。c语言专注于过程式编程和系统级开发,以简洁、高效著称。c++作为c语言的超集,引入了面向对象编程,增强了代码组织和管理能力,但学习曲线也更陡峭。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

327

5

c语言和c++先学哪个好
c语言和c++先学哪个好

初学者选择学习c语言还是c++语言,需要根据个人学习目标、背景以及编程兴趣和预期应用方向来决定。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

426

5

c语言和c++的区别和联系
c语言和c++的区别和联系

c语言和c++是计算机科学领域应用广泛的编程语言。虽然它们有着相似的基础,但它们在语言类型、语法功能和内存管理方面存在着显著差异。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

600

5

c++软件中文更改教程
c++软件中文更改教程

对于 ide,可通过打开设置,找到语言设置,选择中文,并保存更改。对于非 ide 应用程序,可查找设置或选项,选择语言设置,更改为中文,并保存更改。想了解更多c++的相关内容,可以阅读本专题下面的文章。

2024.03.21

1409

9

python和java和c++学习性价比分析
python和java和c++学习性价比分析

Python以其易学性、丰富的库和活跃的社区而著称,适合数据科学、人工智能和Web开发。Java以其跨平台性、企业级应用开发和Android应用开发而闻名。C++以其底层控制能力、高效性能和游戏开发而著称。选择哪种语言取决于个人兴趣、职业方向和特定需求。想了解更多python和java和c++的相关内容,可以阅读本专题下面的文章。

2024.03.22

1217

7

c++和c语言学习顺序推荐
c++和c语言学习顺序推荐

对于初学者,建议先学习C语言,掌握编程基础后再转入C++,便于理解面向对象编程概念。有编程经验者可直接学习C++,快速接触高级编程技术。想了解更多c++和c语言的相关内容,可以阅读本专题下面的文章。

2024.03.25

1325

9

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习

C++ 官方标准说明
C++ 官方标准说明

共0课时 | 0人学习