惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

J
Java Code Geeks
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
有赞技术团队
有赞技术团队
博客园 - 【当耐特】
云风的 BLOG
云风的 BLOG
Martin Fowler
Martin Fowler
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
量子位
Engineering at Meta
Engineering at Meta
博客园 - 叶小钗
T
The Blog of Author Tim Ferriss
Recent Announcements
Recent Announcements
罗磊的独立博客
B
Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
U
Unit 42
Microsoft Azure Blog
Microsoft Azure Blog
D
Docker
N
Netflix TechBlog - Medium
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
B
Blog RSS Feed
I
InfoQ
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
V
V2EX

博客园 - 干炸小黄鱼

timex 处理时间戳 gorm-gen go 雪花算法 golang每日一库--协程池库ants golang每日一库--json解析库gjson python高级编程-asyncio python高级编程-condition python装饰器-自动重试 EAP系统 go实现实现 SECS/GEM 协议 设备通信协议 SECS go项目使用Jenkins进行CICD go操作ES mongo db聚合查询 go如何使用mongodb Apache ShardingSphere paxos and raft (分布式一致性算法) go使用zookeeper分布式锁以及和redis差异 go使用 seata 示例 Alibaba 分布式事务 Seata go中使用saga go中使用TCC示例 分布式事务TCC 熔断器 Hystrix OR Sentinel k8s下部署consul and etcd Consul OR Etcd 【力扣hot100】双指针-盛水最多的容器 【力扣hot100】滑动窗口-最小覆盖子串 shell脚本合集 分布式id生成器
python高级编程-event
干炸小黄鱼 · 2026-05-09 · via 博客园 - 干炸小黄鱼

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
      两者的用法完全一样,但千万不能混用,因为线程和进程的内存空间是隔离的。