Fiber 凭什么比线程快 50 倍——从用户态栈切换到 N:M 调度器,追踪有栈协程的 3 层实现
在同一台 Intel i7-12700(Linux 6.1、GCC 13.2、-O2 优化)上跑一个最简单的 ping-pong 切换基准测试——两个执行体交替切换 100 万次,统计单次切换的平均耗时——pthread 版本(通过pthread_cond_signal/pthread_cond_wait交替唤醒)稳定在 1.8 微秒左右,而 Boost.Context 1.83 的jump_fcontext版本只需要 18 纳秒,差了整整 100 倍。这不是某个特殊场景下的极端数据,而是你在任何一台现代 x86_64 Linux 机器上都能复现的基本事实:用户态的上下文切换,比内核态的线程切换快两个数量级。但如果你仔细想一下"快 100 倍"这个数字的构成——1.8 微秒里面到底有哪些开销?18 纳秒的 Fiber 切换省掉了其中的哪些步骤、保留了哪些步骤?——你会发现,绝大多数讲"协程比线程轻量"的文章,都只说到了"因为没有 syscall 所以快"这一层,而这一层的贡献其实只占整个性能差距的不到 20%。真正让 Fiber 比线程快 50-100 倍的原因,不是某一个单独的优化,而是一套三层架构在每一层上系统性地消除内核态开销的结果:第一层是上下文切换——用 10 行汇编替代操作系统的整套寄存器保存/恢复 + 调度决策流程;第二层是栈管理——用 mmap + guard page 替代内核为每个线程预分配的 8MB 栈空间;第三层是调度器——用用户态的 N:M 调度器替代内核的 CFS/O(1) 调度器,在完全不陷入内核的情况下完成任务切换。这篇文章将逐层拆解