condition适用于“等某个条件成立再继续”的协作场景,需在with块内调用wait(),用while循环检查条件以防虚假唤醒;event适合广播式通知,仅表示事件是否发生,不可替代condition实现精确状态等待。

Condition 适合「等某个条件成立再继续」的协作场景
当你需要多个线程协调执行顺序,比如「生产者等缓冲区有空位,消费者等缓冲区有数据」,Condition 就是为这种「状态依赖」设计的。它本质是带锁的等待队列,内部绑定了一个 Lock(默认是 RLock),所以你不用手动管理锁的获取与释放——但正因如此,容易误用。
- 必须在
with condition:块内调用wait(),否则会抛RuntimeError: cannot wait on un-acquired lock -
notify()和notify_all()不会释放锁,只是唤醒等待线程;被唤醒的线程仍需重新竞争锁,拿到后才从wait()返回 - 永远用 while 循环检查条件,而不是 if:因为存在虚假唤醒(spurious wakeup)或条件在唤醒后又被其他线程改回
- 示例中常见错误是把条件判断写在
wait()外面,导致错过信号或死锁
Event 更适合「广播式通知:一件事发生了,所有关心它的线程都该知道」
Event 是轻量级的二值信号量,只有 set() 和 clear() 两种状态,没有内置锁、不关心「谁设的」「为什么设的」,只回答「是否发生过」。它不保证顺序,也不传递数据,所以别指望靠它实现生产者-消费者那样的精确同步。
- 多个线程调用
wait()会同时被唤醒,但不会排队——这和Condition.notify_all()表现类似,但语义不同:一个是「广播事件」,一个是「通知条件可能变了」 -
Event的is_set()是线程安全的,但不能替代条件变量的原子性检查;它适合做启动门控(如主线程等所有子线程就绪)、终止信号(如stop_event.set()) - 注意:
Event一旦set(),就会一直保持 True,直到显式clear();如果漏掉clear(),后续wait()会立刻返回,造成逻辑错乱
别用 Event 替代 Condition 实现「等待特定值」
有人图省事,用 Event 模拟「等 count == 5」:主线程循环检查 if shared_count == 5: event.set(),子线程 event.wait()。这看似可行,实则危险。
MoChat 是开源的企业微信应用开发框架&引擎,是一套通用的企业微信多租户SaaS管理系统,得益于 Swoole 和 Hyperf 框架的优秀,MoChat 可提供超高性能的同时,也保持着极其灵活的可扩展性。应用场景可用于电商、金融、零售、餐饮服装等服务行业的企业微信用户,通过简单的分流、引流转化微信客户为企业客户,结合强大的后台支持,灵活的运营模式,建立企业与客户的强联系,让企业的盈利
- 竞态明显:子线程可能在主线程检查前就执行了
wait(),而主线程又在子线程进入等待后才set(),导致永久阻塞 - 没有原子性保障:
shared_count本身不是线程安全的,即使加锁,也无法让wait()和条件检查形成原子对 - 正确做法只能是
Condition:在锁保护下检查条件,并用wait()主动让出 CPU,由信号驱动重试
性能与可维护性差异常被低估
单看 API,Event 更简单,Condition 更啰嗦。但实际项目里,选错类型会让调试成本飙升——尤其是多线程逻辑嵌套时。
立即学习“Python免费学习笔记(深入)”;
-
Event的等待不关联任何上下文,日志里看到event.wait()阻塞,你得翻遍代码找谁set()、什么时候clear()、有没有重复set() -
Condition虽然要写更多行,但每个wait()都明确绑定在某个条件判断上,配合注释,意图清晰得多 - CPython 下两者底层都基于系统原语(如 futex 或 Windows event),性能差异微乎其微;真正拖慢的是逻辑混乱带来的反复加锁、误唤醒、忙等待
最常被忽略的一点:Condition 的 wait() 可能被信号中断(比如 Ctrl+C),在某些环境下会抛 InterruptedError;如果没包在 try/except 里,程序可能静默退出。这不是 bug,是 POSIX 行为,但很少人记得处理。









