[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,不阻塞。

python 复制代码
async def main():
    task1 = asyncio.create_task(fetch_a())   # 立即调度,不等完成
    task2 = asyncio.create_task(fetch_b())   # 两个协程并发运行
    result_a = await task1                   # 需要结果时再 await
    result_b = await task2

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


2. asyncio.to_thread(func, *args)

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

python 复制代码
async def main():
    # time.sleep 是同步阻塞的,直接调用会卡死整个 loop
    await asyncio.to_thread(time.sleep, 5)   # 丢到线程池,loop 继续处理别的

    # 典型场景:CPU 密集计算、没有 async 版本的阻塞 IO 库
    data = await asyncio.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

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

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


相关 API:call_soon_threadsafe

python 复制代码
loop.call_soon_threadsafe(callback, *args)

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

python 复制代码
# 从 WebSocket 线程把音频流注册到主线程的 Mixer
self._main_loop.call_soon_threadsafe(mixer.add_stream, stream)

总结对比表

API 调用位置 投递目标 方向 返回值
create_task(coro) 协程内 协程 → 同一个 loop async → async asyncio.Task
to_thread(func) 协程内 同步函数 → 线程池 async → sync → async awaitable
run_coroutine_threadsafe(coro, loop) 任意线程 协程 → 另一个线程的 loop sync → async concurrent.futures.Future
call_soon_threadsafe(cb) 任意线程 回调 → 另一个线程的 loop sync → 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
相关推荐
雪碧聊技术3 小时前
安装Python(保姆级教程)
python·版本更新·python下载
张龙6876 小时前
uv 全面指南:比 pip 快 100 倍的 Python 包管理器,从安装到团队落地
后端·python
@HNUSTer6 小时前
Python数据可视化科技图表绘制系列教程(八)
python·数据可视化·科技论文·专业制图·科研图表
专注仿真7 小时前
问答大模型技术方案算法实现-熵权法融合算法 + 交叉编码器重排算法
人工智能·python·算法·语言模型·问答大模型关键算法·熵权融合算法·交叉编码器重排算法
满怀冰雪8 小时前
22-使用 PaddleClas 快速训练图像分类模型
人工智能·python·机器学习·分类·数据挖掘·paddlepaddle
gb42152878 小时前
python中Web应用服务器
开发语言·前端·python
reasonsummer10 小时前
【办公类-109-12】20260901圆形挂牌(模版重制:文本框圆形重叠_word编辑单面_接送卡&被子卡&床卡&入园卡)
python·word
名明鸣冥10 小时前
k8s-agent架构思考(一)
python
DoLovya10 小时前
从零实现 ESP8266 + MQTT 智能门禁:公网一键开门、舵机控制、在线监控完整方案
python·物联网·mqtt·嵌入式·esp8266·门禁系统
AI情绪识别开源10 小时前
检信ALLEMOTION VibrationAI 2.4.0 12维度情绪识别开源源代码
开发语言·python