扩展 Python 事件机制:支持等待事件消失
标签:#Python #并发编程 #事件机制 #异步编程
日期:2026-05-19
摘要:Python 的
threading.Event只能等待事件"发生",但人类的自然认知中,事件应该有"发生"和"消失"两种状态。本文介绍如何扩展事件对象,让它同时支持等待事件发生和等待事件消失,用起来更符合直觉。
前言
在 Python 中,threading.Event 是常用的线程同步机制。但用它的时候,我总感觉哪里不对劲。后来我意识到问题所在:事件有"发生"和"消失"两种状态,但我们只能等待"发生" ,不能等待事件消失。今天就来分享我的解决方案------扩展的事件对象。
一、传统事件机制的痛点
🎯 threading.Event 的用法
python
from threading import Event
event = Event()
# 线程A: 设置事件
event.set() # 事件发生
# 线程B: 等待事件
event.wait() # 等待事件发生
😅 使用中的别扭感
假设一个场景:等待下载完成,然后下载完成后再等待下载开始。
用传统的方式,你会发现很难表达:
python
# 问题:下载完成后,我想等待"下载开始"这个事件再次触发
# 但 set() 之后,wait() 就永远返回了,除非调用 clear()
event = Event()
event.set() # 下载完成
# 这里我们想等待"下一次下载开始"
# 但 wait() 立即返回,因为事件已经是"发生"状态
event.wait() # ❌ 立即返回,不是我想要的
核心问题:传统 Event 只有两种状态,但现实中的事件有生命周期:
- 发生 → 持续 → 消失
我们天然地认为事件有两种等待方式:等它来,或等它走。
二、扩展事件对象的设计
🎯 设计目标
- 支持两种等待 :
wait_appear(): 等待事件发生wait_disappear(): 等待事件消失
💻 实现代码
python
import threading
class MyEvent:
"""多线程事件,支持等待事件发生与等待事件消失。"""
def __init__(self):
# 内部使用两个 Event,避免轮询
self._occurred = threading.Event() # 事件发生时为 True
self._disappeared = threading.Event() # 事件消失时为 True
self._disappeared.set() # 初始状态:事件未发生,消失状态成立
self._lock = threading.Lock()
def fire(self):
"""触发事件(设置事件发生)。"""
with self._lock:
self._occurred.set()
self._disappeared.clear()
def clear(self):
"""清除事件(让事件变为未发生)。"""
with self._lock:
self._occurred.clear()
self._disappeared.set()
def wait_occur(self, timeout=None)->bool:
"""等待事件发生,直到被 fire() 或超时。
返回 True 表示事件发生,False 表示超时。
"""
return self._occurred.wait(timeout)
def wait_disappear(self, timeout=None)->bool:
"""等待事件消失,直到被 clear() 或超时。
返回 True 表示事件已消失,False 表示超时。
"""
return self._disappeared.wait(timeout)
def is_set(self)->bool:
"""查询当前事件是否处于发生状态。"""
return self._occurred.is_set()
三、使用示例
python
import time
import threading
def worker(evt):
print("子线程:等待事件发生...")
if evt.wait_occur(5):
print("子线程:检测到事件发生,开始工作")
else:
print("子线程:超时,事件未发生")
print("子线程:等待事件消失...")
if evt.wait_disappear(5):
print("子线程:事件已消失,后续处理")
else:
print("子线程:超时,事件仍未消失")
evt = MyEvent()
t = threading.Thread(target=worker, args=(evt,))
t.start()
time.sleep(1)
evt.fire() # 触发事件
time.sleep(1)
evt.clear() # 清除事件
t.join()
四、与传统 Event 的对比
| 功能 | threading.Event | Event2 |
|---|---|---|
| 等待事件发生 | ✅ wait() |
✅ wait_occur() |
| 等待事件消失 | ❌ 不支持 | ✅ wait_disappear() |
| 链式等待 | ❌ 不支持 | ✅ 可以支持(等待事件发生之后再消失) |
- 后续还可以加入回调机制
六、总结
📌 本文要点
| 概念 | 说明 |
|---|---|
| 传统 Event 的局限 | 只能等待"发生",无法等待"消失" |
| 扩展的 Event2 | 同时支持 wait_occur() 和 wait_disappear() |
| 可以支持链式等待 | wait_appear_then_disappear() / wait_disappear_then_appear() |
| 更符合直觉 | 事件有生命周期:发生 → 持续 → 消失 |
📚 参考资料
本文为本人原创,首发于掘金。
如果你有任何问题或想法,欢迎在评论区交流!