python高级编程-event

Python 中的 Event 对象是多线程(threading)和多进程(multiprocessing)编程中非常经典且实用的线程/进程同步工具

你可以把它通俗地理解为一个“全局的信号灯”或“开关”。它内部维护着一个布尔值(标志位),默认是 False(红灯/关)。

  • 当标志位为 False 时,等待它的线程/进程会被阻塞(卡住)。
  • 当标志位被设置为 True 时,所有等待它的线程/进程会被唤醒,继续往下执行。

下面我将从核心方法、基础用法到实战案例,带你一步步掌握它。

💡 Event 的核心方法

无论是 threading.Event 还是 multiprocessing.Event,它们都提供了完全相同的 4 个核心方法:

方法 作用 通俗解释
event.set() 将标志位设为 True 把信号灯变绿,唤醒所有等待的线程
event.clear() 将标志位设为 False 把信号灯变红,让等待的线程继续阻塞
event.wait(timeout=None) 阻塞等待标志位变为 True 遇到红灯就停车等待;timeout 可设置最长等多久
event.is_set() 检查当前标志位是否为 True 看看现在是不是绿灯

🛠️ 基础用法:线程间的“发令枪”

假设我们有一个场景:主线程需要做一些准备工作(比如加载数据),在准备好之前,工作线程必须原地等待。

import threading
import time

# 1. 创建一个 Event 对象,默认状态是 False (红灯)
ready_event = threading.Event()

def worker():
    print("工作线程:我已经就位,正在等待主线程的信号...")
    # 2. 调用 wait(),如果标志位是 False,线程会在这里阻塞(卡住)
    ready_event.wait() 
    print("工作线程:收到信号!开始执行任务!")

def main():
    t = threading.Thread(target=worker)
    t.start()
    
    print("主线程:正在做准备工作,需要 3 秒钟...")
    time.sleep(3)
    
    print("主线程:准备完毕,发出信号!")
    # 3. 调用 set(),将标志位设为 True,唤醒所有等待的线程
    ready_event.set()

if __name__ == '__main__':
    main()

执行流程: worker 线程启动后会卡在 wait() 这一行。直到 3 秒后主线程执行了 set()worker 线程才会被唤醒并打印“开始执行任务”。


🚀 实战案例:模拟服务的“优雅停止”

这是 Event 在生产环境中最常用的模式。相比于强制杀死线程(terminate),使用 Event 作为停止信号可以让线程安全地释放资源、保存状态后再退出。

import threading
import time

# 创建一个停止信号事件
stop_event = threading.Event()

def background_task():
    """模拟一个在后台持续运行的周期性任务"""
    while not stop_event.is_set():  # 只要停止信号没被触发,就一直运行
        print("后台任务:正在处理数据...")
        time.sleep(1)
    # 循环结束后,执行退出前的清理工作
    print("后台任务:收到停止信号,正在安全退出并保存状态...")

def main():
    t = threading.Thread(target=background_task)
    t.start()
    
    print("主程序:让后台任务运行 5 秒钟...")
    time.sleep(5)
    
    print("主程序:任务结束,通知后台线程退出。")
    # 触发停止信号
    stop_event.set()
    
    # 等待后台线程彻底执行完退出逻辑
    t.join()
    print("主程序:所有线程已安全退出。")

if __name__ == '__main__':
    main()

⚠️ 避坑指南与进阶提示

  1. wait() 建议带上超时时间
    在调用 event.wait() 时,强烈建议加上 timeout 参数(例如 event.wait(timeout=5))。这样可以防止因为逻辑错误导致事件永远没有被 set(),从而使线程陷入死锁(无限期卡死)。
  2. Event 是一次性信号
    Event 一旦被 set() 变成 True,它就会一直保持 True。如果后续还有线程调用 wait(),它们会直接通过,不会再阻塞。如果你想重复使用它(比如模拟红绿灯反复切换),记得在合适的时机调用 event.clear() 把它重置为 False
  3. 区分 threading.Eventmultiprocessing.Event
    • 如果你在写多线程程序,请使用 from threading import Event
    • 如果你在写多进程程序,请使用 from multiprocessing import Event
      两者的用法完全一样,但千万不能混用,因为线程和进程的内存空间是隔离的。
posted @ 2026-05-09 10:11  干炸小黄鱼  阅读(32)  评论(0)    收藏  举报