news 2026/5/12 11:34:06

Python `asyncio` 与 C++ Fiber 的原理与逻辑分析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python `asyncio` 与 C++ Fiber 的原理与逻辑分析

1.异同点

Pythonasyncio和 C++ fiber 都属于协作式并发模型:任务不会被操作系统强制抢占,而是在遇到某些“让出执行权”的点时主动暂停,让调度器运行其他任务。

但二者的抽象层级不同:

维度PythonasyncioC++ Fiber
核心抽象coroutineTaskFuture、event loopfiber、scheduler、上下文切换
调度方式event loop 调度 coroutinescheduler 调度 fiber
让出点awaityield/ 阻塞点被 fiber runtime 接管
栈模型通常是无栈协程 stackless coroutine通常是有栈协程 stackful coroutine
典型用途高并发 I/O、网络服务、异步任务编排高性能服务、游戏服务器、用户态线程、复杂控制流
语言/库关系Python 标准库内置运行时C++ 无统一标准 fiber runtime,常依赖库

一句话概括:

asyncio是围绕事件循环构建的异步 I/O 协程框架;C++ fiber 更像用户态轻量线程,由运行时调度并进行用户态上下文切换。


2. Pythonasyncio的原理

2.1 基本组成

Pythonasyncio主要由以下几个部分组成:

coroutine -> Task -> event loop -> selector / proactor / I/O backend

常见对象包括:

概念作用
async def定义 coroutine function
coroutine object调用async def后得到的可等待对象
await挂起当前 coroutine,等待另一个 awaitable 完成
asyncio.Task把 coroutine 包装成可被 event loop 调度的任务
asyncio.Future表示一个未来会完成的结果
event loop调度任务、监听 I/O、处理 timer、回调等
asyncio.gather()并发等待多个 awaitable

2.2 coroutine 的执行逻辑

示例:

importasyncioasyncdeffetch():print("start")awaitasyncio.sleep(1)print("end")return42asyncio.run(fetch())

执行逻辑大致如下:

1. 调用 fetch(),不会立即执行函数体,而是返回 coroutine object 2. asyncio.run() 创建 event loop 3. event loop 把 coroutine 包装成 Task 4. Task 开始执行 coroutine 5. 遇到 await asyncio.sleep(1) 6. 当前 coroutine 挂起,控制权返回 event loop 7. event loop 可以运行其他 Task 8. 1 秒后 timer 到期,event loop 恢复该 coroutine 9. coroutine 继续执行并返回结果

关键点:

await 不是阻塞线程,而是挂起当前 coroutine。

2.3 event loop 的角色

event loop 是asyncio的调度中心。

它大致做这些事情:

while True: 1. 执行 ready queue 中可运行的回调和 Task 2. 检查 timer 是否到期 3. 等待 I/O 事件 4. I/O 就绪后,把对应 Task 放回 ready queue 5. 重复

可以理解为:

event loop = cooperative scheduler + I/O multiplexer + timer manager

在 Linux 上,底层常见机制是epoll;在 macOS/BSD 上常见是kqueue;在 Windows 上可能是 IOCP 或 selector 机制。开发者一般不直接操作这些底层接口,而是通过asyncio抽象使用。


2.4await的本质

await的作用是:

当前 coroutine 暂停执行,把控制权交还给 event loop。

逻辑上类似:

result = await something

可拆成:

1. 当前 coroutine 依赖 something 的完成结果 2. 当前 coroutine 暂停 3. event loop 继续执行其他任务 4. something 完成后,当前 coroutine 被重新调度 5. await 表达式返回结果

所以:

await = 协作式让出控制权 + 等待结果

2.5asyncio.gather()的逻辑

results=awaitasyncio.gather(task1(),task2(),task3())

含义是:

1. 把多个 coroutine / Task 注册到 event loop 2. 让它们并发推进 3. 当前 coroutine 等待所有任务完成 4. 返回所有任务的结果列表

等价于 C++ 生态中常说的:

when_all(task1, task2, task3)

但需要注意:

asyncio.gather() 不是多线程并行。

默认情况下,它们仍然运行在同一个线程的同一个 event loop 上。并发来自于 I/O 等待期间的任务切换,而不是 CPU 并行。


3. C++ Fiber 的原理

3.1 Fiber 是什么

Fiber 通常被称为:

用户态线程 轻量线程 有栈协程 stackful coroutine

它和 OS thread 的区别是:

维度OS ThreadFiber
调度者操作系统内核用户态 scheduler
切换成本较高,需要内核参与较低,通常用户态完成
每个线程有自己的栈每个 fiber 通常也有自己的栈
抢占通常可抢占通常协作式
并行性多核并行单线程内不并行,多线程调度器可并行

Fiber 的核心思想:

把“执行上下文”保存起来,在用户态切换到另一个执行上下文。

一个 fiber 一般包含:

1. 独立栈空间 2. 寄存器上下文 3. instruction pointer / program counter 4. 状态信息 5. 调度器相关元数据

3.2 Fiber 的执行逻辑

伪代码:

voidfiber_func(){std::cout<<"A\n";fiber_yield();std::cout<<"B\n";}

执行逻辑:

1. scheduler 创建 fiber,并分配栈 2. fiber 开始执行 fiber_func 3. 输出 A 4. 调用 fiber_yield() 5. 保存当前 fiber 的寄存器、栈指针、指令位置 6. scheduler 选择另一个 fiber 执行 7. 之后某个时刻,scheduler 恢复这个 fiber 8. fiber 从 yield 后继续执行 9. 输出 B

关键点:

fiber_yield() 不是退出函数,而是暂停整个调用栈。

3.3 Stackful 与 Stackless

这是理解asyncio与 fiber 差异的关键。

Pythonasyncio: 通常是 stackless

asynciocoroutine 是无栈协程。

这意味着:

只有 coroutine 自己的状态机会被保存。 普通函数调用栈不会整体挂起。

示例:

asyncdefa():awaitb()asyncdefb():awaitc()

只有async函数链路可以被await挂起。普通同步函数内部不能直接await

例如:

defnormal_func():awaitsomething# 语法错误

因为普通函数不是 coroutine,无法被 event loop 挂起和恢复。


C++ Fiber: 通常是 stackful

Fiber 是有栈协程。

它可以在深层普通函数调用中 yield:

voiddeep_function(){fiber_yield();}voidmiddle_function(){deep_function();}voidfiber_main(){middle_function();}

deep_function()调用fiber_yield()时,整个调用栈都会被暂停。

这意味着:

fiber 可以挂起整个调用栈; asyncio coroutine 通常只能在 async/await 链路上挂起。

3.4 Fiber scheduler

Fiber 需要 scheduler 来决定:

1. 哪个 fiber 当前可运行 2. 当前 fiber yield 后切换到哪个 fiber 3. I/O 未就绪时如何挂起 fiber 4. I/O 就绪时如何恢复 fiber 5. 是否支持多个 OS thread 上的 work stealing

一个简单 scheduler 的逻辑:

ready_queue = [] while not ready_queue.empty(): fiber = ready_queue.pop() switch_to(fiber) if fiber.finished: destroy(fiber) elif fiber.waiting: put_to_wait_list(fiber) else: ready_queue.push(fiber)

如果要支持异步 I/O,scheduler 还需要结合:

epoll / kqueue / IOCP timer mutex / condition variable network runtime

4.asyncio与 C++ Fiber 的核心映射

PythonasyncioC++ Fiber 生态中的近似概念
coroutinecoroutine / fiber task
asyncio.Taskfiber / scheduled task
event loopscheduler / reactor / executor
awaityield / suspend / wait
asyncio.gather()when_all
asyncio.Futurefuture / promise
ready queuerunnable fiber queue
callbackcontinuation
cancellationcancellation token / task cancellation
asyncio.sleep()timer-based suspend
async I/Onon-blocking I/O + scheduler integration

5. 调度模型对比

5.1asyncio调度

asyncio的调度单位是 coroutine wrapped by Task。

Task A runs -> await I/O -> Task A suspended event loop runs Task B -> await timer -> Task B suspended I/O ready -> Task A resumes timer ready -> Task B resumes

特点:

1. 单线程事件循环为主 2. I/O 驱动 3. await 是明确的切换点 4. 不会在任意 Python 字节码之间切换 5. 适合大量 I/O-bound 任务

5.2 Fiber 调度

Fiber 的调度单位是 fiber。

Fiber A runs -> yield / wait socket -> scheduler switches to Fiber B Fiber B runs -> yield / wait timer -> scheduler switches to Fiber C socket ready -> scheduler resumes Fiber A

特点:

1. 可在用户态切换完整调用栈 2. 调度器由库或框架实现 3. 可以做得像同步代码一样 4. I/O 阻塞点通常需要 runtime hook 5. 适合复杂控制流和高性能服务

6. 挂起与恢复机制

6.1asyncio的挂起

asyncio挂起 coroutine 时,保存的是:

1. coroutine 的状态 2. 当前执行位置 3. 局部变量 4. 等待的 Future / Task

不保存完整 C 调用栈。

所以它更像:

状态机

例如:

asyncdeff():x=1awaitg()y=2

可粗略理解为被转换成:

state 0: x = 1 wait g() state = 1 return to event loop state 1: y = 2 finish

6.2 Fiber 的挂起

Fiber 挂起时,保存的是:

1. 栈指针 2. 指令指针 3. 寄存器 4. fiber 栈内容

恢复时:

1. 恢复栈指针 2. 恢复寄存器 3. 跳回之前暂停的位置 4. 继续运行

因此 fiber 更像:

轻量级线程上下文切换

7. I/O 模型差异

7.1asyncioI/O

asyncio强依赖非阻塞 I/O。

例如:

reader,writer=awaitasyncio.open_connection("example.com",80)

背后逻辑:

1. socket 设置为 non-blocking 2. 发起 connect/read/write 3. 如果不能立即完成,注册到 event loop 4. event loop 监听 fd 是否就绪 5. 就绪后恢复对应 Task

如果在asyncio中调用普通阻塞函数:

time.sleep(10)

会阻塞整个 event loop。

正确做法是:

awaitasyncio.sleep(10)

或者把阻塞任务放入线程池:

awaitasyncio.to_thread(blocking_func)

7.2 Fiber I/O

Fiber 生态中常见两种方式:

方式一:显式异步 I/O
fiber 调用 async_read 如果未就绪,则 yield I/O 完成后 scheduler 恢复 fiber
方式二:hook 阻塞 I/O

某些 fiber runtime 会 hook 常见阻塞系统调用,例如:

read write connect sleep mutex lock

让开发者写同步风格代码:

autodata=socket.read();

但底层实际逻辑是:

1. socket 未就绪 2. 当前 fiber 挂起 3. scheduler 运行其他 fiber 4. socket 就绪 5. 当前 fiber 恢复

这也是 fiber 很有吸引力的地方:

代码看起来同步,运行时行为却是异步协作调度。

8. 错误传播与取消

8.1asyncio

asyncio中异常会沿await传播:

asyncdefchild():raiseRuntimeError("error")asyncdefmain():awaitchild()

main()会收到RuntimeError

gather()的错误行为需要特别注意:

awaitasyncio.gather(a(),b(),c())

默认情况下,如果其中一个 awaitable 抛异常,gather()会向调用方传播该异常。其他任务的处理行为取决于具体版本和调用方式,需要根据语义谨慎设计。

取消任务:

task.cancel()

会向 coroutine 注入CancelledError


8.2 C++ Fiber

C++ fiber 的错误传播取决于具体库。

常见方式包括:

1. exception_ptr 保存异常 2. future/promise 传播异常 3. scheduler 捕获顶层异常 4. task join 时重新抛出异常

取消通常依赖:

1. cancellation token 2. stop_token 3. 自定义标志位 4. runtime-specific cancellation

C++ 本身没有统一的 fiber 取消语义。


9. 并发与并行

9.1asyncio

asyncio默认是单线程并发:

多个 Task 交替运行,但同一时刻只有一个 Task 在 Python 线程中执行。

适合:

1. 网络 I/O 2. 文件/数据库异步驱动 3. WebSocket 4. HTTP 客户端/服务端 5. 大量等待型任务

不适合直接处理大量 CPU-bound 计算。

CPU-bound 场景需要:

1. multiprocessing 2. ProcessPoolExecutor 3. C 扩展释放 GIL 4. 外部计算服务

9.2 Fiber

Fiber 在单个 OS thread 上也是并发,不是并行。

但 C++ fiber runtime 可以设计成:

多个 OS thread 每个 thread 一个 scheduler fiber 在 thread 间迁移 work stealing

这时可以实现:

M:N 调度模型

即:

M 个 fiber 映射到 N 个 OS thread

这样可以同时获得:

1. 用户态轻量调度 2. 多核并行能力

10. 性能特点

10.1asyncio

优点:

1. Python 标准库内置 2. 生态成熟 3. 非常适合 I/O-bound 高并发 4. 任务创建成本低于线程 5. 编程模型清晰,await 点显式

缺点:

1. 单线程 event loop 容易被阻塞 2. CPU-bound 任务受 GIL 影响 3. async/await 会污染调用链 4. 所有阻塞库都需要 async 版本或放入线程池 5. 调试复杂并发时需要理解 Task 状态

10.2 C++ Fiber

优点:

1. 切换成本低于 OS thread 2. 可保留同步代码风格 3. 有栈模型适合复杂调用链 4. 可构建高性能网络运行时 5. 可以与多线程结合实现 M:N 调度

缺点:

1. C++ 标准库没有统一 fiber 2. 依赖具体 runtime 或第三方库 3. 栈大小、生命周期、调度策略需要谨慎管理 4. 与阻塞系统调用集成复杂 5. 调试上下文切换和竞态问题可能困难

11. 典型代码风格对比

11.1 Pythonasyncio

importasyncioasyncdefworker(name,delay):print(f"{name}start")awaitasyncio.sleep(delay)print(f"{name}done")returnnameasyncdefmain():results=awaitasyncio.gather(worker("A",1),worker("B",2),worker("C",3),)print(results)asyncio.run(main())

逻辑:

main coroutine -> gather creates/schedules workers -> workers hit await sleep -> event loop handles timers -> all workers complete -> gather returns results

11.2 C++ Fiber 风格伪代码

不同 fiber 库 API 不统一,以下是抽象伪代码:

voidworker(std::string name,intdelay){std::cout<<name<<" start\n";fiber_sleep(delay);std::cout<<name<<" done\n";}intmain(){Scheduler scheduler;scheduler.spawn([]{worker("A",1);});scheduler.spawn([]{worker("B",2);});scheduler.spawn([]{worker("C",3);});scheduler.run();}

逻辑:

scheduler starts Fiber A -> Fiber A calls fiber_sleep -> Fiber A suspended scheduler starts Fiber B -> Fiber B suspended scheduler starts Fiber C -> Fiber C suspended timer ready -> resume corresponding fiber

12.awaityield的逻辑差异

维度awaitfiberyield
表达含义等待某个 awaitable 完成主动让出执行权
是否绑定结果通常绑定结果不一定
调度目标event loopfiber scheduler
挂起范围当前 coroutine当前 fiber 的整个调用栈
调用限制只能在async def中使用通常可在 fiber 上下文中的普通函数中使用
编译/运行时模型状态机式 coroutine上下文切换式 coroutine

可以简单理解为:

await = yield + 等待对象 + continuation

而 fiber 的yield更底层:

yield = 保存当前 fiber 上下文,把控制权交给 scheduler

13.asyncio.gather与 C++when_all

13.1asyncio.gather

results=awaitasyncio.gather(a(),b(),c())

语义:

等待 a、b、c 全部完成,返回结果列表。

13.2 C++when_all

C++ 生态中很多异步库提供类似能力:

autoresult=co_awaitwhen_all(task_a(),task_b(),task_c());

语义:

等待多个异步操作全部完成。

但 C++ 标准目前并没有一个 universally available 的std::when_all可直接覆盖所有 coroutine/fiber runtime。不同库的taskfuturesender/receiver、scheduler 模型差异较大。


14. 工程选型建议

14.1 选择 Pythonasyncio的场景

适合:

1. Python 项目 2. 网络 I/O 高并发 3. HTTP API 服务 4. WebSocket 服务 5. 爬虫 6. 异步数据库访问 7. 消息队列消费者 8. 需要快速开发

不适合:

1. CPU 密集型计算 2. 需要极致低延迟 3. 大量依赖同步阻塞库 4. 对运行时调度有强控制需求

14.2 选择 C++ Fiber 的场景

适合:

1. 高性能服务器 2. 游戏服务器 3. RPC 框架 4. 低延迟网络系统 5. 希望用同步风格写异步逻辑 6. 需要 M:N 调度 7. 需要深层调用栈中任意挂起

不适合:

1. 不想维护复杂 runtime 2. 项目团队不熟悉用户态调度 3. 调试工具链不完善 4. 对跨平台稳定性要求很高但库支持不足

15. 最重要的区别总结

15.1 抽象层级不同

asyncio 是一个完整的异步 I/O 框架。 fiber 是一种执行上下文/调度单位。

15.2 栈模型不同

asyncio coroutine 通常是 stackless。 fiber 通常是 stackful。

15.3 代码侵入性不同

asyncio需要 async/await 贯穿调用链:

asyncdefa():awaitb()

fiber 可以让普通同步风格代码运行在可挂起上下文中:

voida(){b();// b 内部可以 yield}

15.4 标准化程度不同

Python asyncio 是标准库。 C++ fiber 没有统一标准运行时。

15.5 并发语义不同

asyncio 更偏事件循环和 Future/Task。 fiber 更偏用户态线程和上下文切换。

16. 总结表

主题PythonasyncioC++ Fiber
本质异步 I/O 框架用户态轻量线程
调度者event loopscheduler
调度方式协作式协作式
切换点awaityield/ runtime wait
无栈有栈
挂起范围当前 coroutine整个 fiber 调用栈
I/O 模型非阻塞 I/O + event loop非阻塞 I/O 或 hook 阻塞 I/O
并行能力默认无,需要线程/进程取决于 runtime,可做 M:N
标准支持Python 标准库C++ 无统一 fiber 标准
编程风格显式 async/await可接近同步风格
适用方向Python 高并发 I/OC++ 高性能并发 runtime

17. 总结

Python asyncio:用 event loop 调度无栈 coroutine,通过 await 显式挂起。 C++ fiber:用 scheduler 调度有栈用户态线程,通过 yield 或 runtime wait 挂起整个调用栈。

如果从概念映射看:

asyncio Task ≈ scheduled fiber event loop ≈ scheduler / reactor await ≈ suspend + yield to scheduler gather ≈ when_all coroutine ≈ coroutine / fiber task

但从实现机制看:

asyncio 更像状态机; fiber 更像用户态线程上下文切换。

经分析fiber在agent复杂任务并行请求调度更有优势.

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/12 11:31:51

从社交推荐到金融风控:链路预测在5个真实业务场景中的落地思考

从社交推荐到金融风控&#xff1a;链路预测在5个真实业务场景中的落地思考 当技术团队被问到"这个算法能带来多少业务增长"时&#xff0c;纯技术实现的讨论往往显得苍白。链路预测作为图计算领域的核心技术之一&#xff0c;其价值不在于算法本身的复杂度&#xff0c;…

作者头像 李华
网站建设 2026/5/12 11:29:34

如何用m4s-converter轻松保存B站缓存视频:个人备份的终极指南

如何用m4s-converter轻松保存B站缓存视频&#xff1a;个人备份的终极指南 【免费下载链接】m4s-converter 一个跨平台小工具&#xff0c;将bilibili缓存的m4s格式音视频文件合并成mp4 项目地址: https://gitcode.com/gh_mirrors/m4/m4s-converter 你是否曾经遇到过这样的…

作者头像 李华
网站建设 2026/5/12 11:28:34

如何为iOS 14.0-16.6.1设备安装TrollStore:TrollInstallerX完整指南

如何为iOS 14.0-16.6.1设备安装TrollStore&#xff1a;TrollInstallerX完整指南 【免费下载链接】TrollInstallerX A TrollStore installer for iOS 14.0 - 16.6.1 项目地址: https://gitcode.com/gh_mirrors/tr/TrollInstallerX 如果你正在寻找一种可靠且简单的方法在i…

作者头像 李华
网站建设 2026/5/12 11:24:34

3步免费部署img2latex-mathpix:本地化数学公式识别终极指南

3步免费部署img2latex-mathpix&#xff1a;本地化数学公式识别终极指南 【免费下载链接】img2latex-mathpix Mathpix has changed their billing policy and no longer has free monthly API requests. This repo is now archived and will not receive any updates for the fo…

作者头像 李华