当前位置: 首页 > news >正文

[python] asyncio常规操作记录

Python asyncio 并发原语速查手册

Event Loop 执行机制

Event loop 本质是单线程内的无限循环调度器,不断从任务队列取出就绪的任务执行:

while True: events = poll_for_ready_events() # 检查就绪事件(IO完成、定时器到期、回调投递) for event in events: execute(event.callback) # 逐个执行

协程遇到await挂起自身、让出控制权给 loop,loop 去执行其他就绪任务;
等待的操作完成后,loop 恢复该协程继续执行。

一个线程最多运行一个 event loop。


三个核心 API 对比

1.asyncio.create_task(coro)

在当前 loop 内并发调度一个协程,立即返回asyncio.Task,不阻塞。

asyncdefmain():task1=asyncio.create_task(fetch_a())# 立即调度,不等完成task2=asyncio.create_task(fetch_b())# 两个协程并发运行result_a=awaittask1# 需要结果时再 awaitresult_b=awaittask2

适用场景:同一个 loop 内同时跑多个异步 IO 任务(并发请求、并发监听等)。


2.asyncio.to_thread(func, *args)

把同步阻塞函数丢到线程池执行,当前协程挂起等待结果,但 event loop 不阻塞。

asyncdefmain():# time.sleep 是同步阻塞的,直接调用会卡死整个 loopawaitasyncio.to_thread(time.sleep,5)# 丢到线程池,loop 继续处理别的# 典型场景:CPU 密集计算、没有 async 版本的阻塞 IO 库data=awaitasyncio.to_thread(read_big_file,path)

适用场景:调用没有 async 版本的阻塞函数(文件 IO、CPU 计算、旧的同步库),
避免卡死 event loop。

await会卡住当前协程吗?

当前协程会等待,但event loop 和其他协程不受影响:

写法当前协程event loop其他协程
time.sleep(5)全卡
await asyncio.to_thread(time.sleep, 5)不卡正常跑
await asyncio.sleep(5)不卡正常跑

3.asyncio.run_coroutine_threadsafe(coro, loop)

从另一个线程向指定 loop 投递一个协程,返回concurrent.futures.Future

# 在非 asyncio 的普通线程中:future=asyncio.run_coroutine_threadsafe(play_audio(data),main_loop)result=future.result(timeout=10)# 阻塞等待结果(在当前线程阻塞,不影响 loop)

适用场景:普通线程需要让某个 event loop 执行一个协程(跨线程投递异步任务)。


相关 API:call_soon_threadsafe

loop.call_soon_threadsafe(callback,*args)

run_coroutine_threadsafe类似,但投递的是普通回调函数而非协程。

# 从 WebSocket 线程把音频流注册到主线程的 Mixerself._main_loop.call_soon_threadsafe(mixer.add_stream,stream)

总结对比表

API调用位置投递目标方向返回值
create_task(coro)协程内协程 → 同一个 loopasync → asyncasyncio.Task
to_thread(func)协程内同步函数 → 线程池async → sync → asyncawaitable
run_coroutine_threadsafe(coro, loop)任意线程协程 → 另一个线程的 loopsync → asyncconcurrent.futures.Future
call_soon_threadsafe(cb)任意线程回调 → 另一个线程的 loopsync → sync(callback)None

速记口诀

create_task → 同 loop 内并发跑协程 to_thread → 把同步阻塞的东西丢出去,别卡我的 loop run_coroutine_threadsafe → 从外面往别人的 loop 里塞协程 call_soon_threadsafe → 从外面往别人的 loop 里塞回调

项目中的实际应用

本项目AudioReceiverServer中存在两个线程各自运行一个 event loop:

主线程 event loop WebSocket 线程 event loop ┌───────────────────┐ ┌───────────────────┐ │ Mixer 协程 │ │ ws.recv() 协程 A │ │ 其他音频处理 ... │ ◄── call_soon │ ws.recv() 协程 B │ │ │ threadsafe │ ws.recv() 协程 C │ └───────────────────┘ └───────────────────┘
  • WebSocket 线程的 loop 同时await多个连接的recv(),谁来数据就恢复谁
  • 需要操作主线程的 Mixer 时,通过call_soon_threadsafe把回调投递到主线程 loop
http://www.jsqmd.com/news/510638/

相关文章:

  • 2026年质量好的系统品牌推荐:广东矩阵系统实力品牌厂家推荐 - 行业平台推荐
  • 嵌入式音频必看:AU-48 模组彻底解决噪音、回音、啸叫难题
  • 小说作者必备:用次元画室5分钟搞定主角视觉形象
  • Visual Components 4.3实战:如何用数字孪生技术优化你的生产线布局(附真实案例)
  • Qwen3-32B-Chat百度开发者关注焦点:RTX4090D部署常见报错与修复速查表
  • 从HTTPS连接被拒到握手成功:一个Java工程师的SSL调试日记
  • 低轨卫星星载软件开发避坑指南:3大致命C语言内存错误(栈溢出/指针悬空/中断竞态)及NASA级防护代码模板
  • ChatTTS结合AIGC工作流:内容创作全链路自动化
  • 实战指南:用Python+OpenCV实现实时视频阴影检测(附代码)
  • internlm2-chat-1.8b长上下文实战:学术论文精读+核心观点提炼全流程
  • Pixel Dimension Fissioner步骤详解:如何导出维度手稿为Markdown/PDF/JSON
  • Esp32WifiManager:轻量级串口Wi-Fi配置管理框架
  • 伏羲天气预报工业部署:中小企业如何用16GB内存服务器稳定运行FuXi
  • 建议收藏:企业常用合同协议范本合集(涵盖合作/股权/人事/工程)
  • Wedecode完全指南:微信小程序源代码还原与安全审计终极工具
  • 阿里开源万物识别实战:手把手教你批量识别展品图片
  • 操盘五式:【心理博弈】
  • GLM-OCR保姆级教程:从Anaconda环境搭建到模型推理测试
  • 日期题目集
  • 邢台曾是鱼米之乡
  • 【无线电力】超材料驱动的无线电力传输WPT系统仿真Matlab代码
  • Stable-Diffusion-V1-5 提示词反向工程:从图像中提取描述与学习提示词技巧
  • MogFace人脸检测模型-WebUI多场景部署:支持华为昇腾CANN生态适配
  • PCB制造全流程解析:从设计到成品的工程实现
  • MCP 2.0协议安全规范实战避坑手册,覆盖TLS 1.3握手劫持、ECDSA密钥泄露、时间戳漂移等8类高危场景应对方案
  • BGE-Large-Zh入门指南:从控制台日志解读模型加载、编码、计算全流程
  • 基于.NET 6和WPF的OpenCVSharp与ReactiveUI学习实践:3D点云数据处...
  • Qwen-Image镜像惊艳案例:RTX4090D解析科研论文插图并生成方法论总结
  • 【亲测好用】数据服务平台能力演示
  • Qwen-Image定制镜像入门必看:RTX4090D+CU DA12.4环境零基础快速上手