asyncio.Event 仅用于同步协程执行时机,不传递数据;其 set() 无参数、wait() 永远返回 None,需配合 Queue 等结构传值。

asyncio.Event 不是用于传递数据的通道,而是用来同步协程执行时机的信号量——它只表达“某个条件已满足”,不携带任何值。
为什么不能用 asyncio.Event 传数据
它的设计目标就是布尔状态:已设置(set())或未设置(clear())。调用 wait() 的协程会挂起直到有人调用 set(),但不会拿到任何参数。试图在 set() 里塞参数会报 TypeError: set() takes no arguments。
常见错误现象:
– 写成 event.set("done") → 直接抛异常
– 以为 await event.wait() 会返回一个值 → 实际永远返回 None
如果你需要带数据的通知,得搭配其他结构,比如:
– asyncio.Queue(推荐,线程/协程安全)
– 普通变量 + asyncio.Lock 保护(仅限简单场景)
– 类属性或闭包变量(需确保写入和读取发生在同一线程/事件循环中)
立即学习“Python免费学习笔记(深入)”;
正确用法:等待某个异步动作完成后再继续
典型场景是“主协程等子任务发信号”,比如后台监控任务检测到文件就绪后通知主流程开始处理:
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
import asyncio
<p>ready = asyncio.Event()</p><p>async def monitor_file():
await asyncio.sleep(2) # 模拟等待文件生成
print("文件已就绪")
ready.set() # 仅发信号,不传内容</p><p>async def process_file():
print("等待文件...")
await ready.wait() # 挂起,直到 set() 被调用
print("开始处理")</p><p>async def main():
await asyncio.gather(monitor_file(), process_file())</p><p>asyncio.run(main())注意点:
– wait() 可被多次调用,只要 event 处于 set 状态,后续 wait() 会立即返回(即“自动重置”不是默认行为)
– 如果需要每次只触发一次,必须手动 clear(),否则第二次 wait() 不会阻塞
– is_set() 可以非阻塞查询当前状态,适合轮询判断
多个协程等待同一个 Event 时的行为
所有正在 wait() 的协程会在 set() 后**几乎同时被唤醒**(取决于调度顺序),没有优先级或 FIFO 保证。
使用场景举例:
– 启动阶段,多个 worker 协程都等待初始化完成信号
– 测试中模拟“所有依赖服务已启动”这一条件
容易踩的坑:
– 忘记 clear() 导致后续测试用例误判(尤其在 pytest 的 async fixtures 中)
– 在 set() 前已有协程调用了 wait(),没问题;但如果 set() 先发生,再 wait(),也会立刻返回——Event 是“记忆性”的,这点和 threading.Event 一致
– 不要跨事件循环复用同一个 asyncio.Event 实例(比如在不同 asyncio.run() 之间),会引发 RuntimeError
最常被忽略的一点:Event 本身不解决竞态,它只是同步开关。如果两个协程同时修改共享数据又依赖 Event 协调,仍需额外加锁或改用 Queue 来串行化访问。

















