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

推荐订阅源

F
Fortinet All Blogs
Microsoft Security Blog
Microsoft Security Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Vercel News
Vercel News
Application and Cybersecurity Blog
Application and Cybersecurity Blog
C
Check Point Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
W
WeLiveSecurity
The Hacker News
The Hacker News
L
LINUX DO - 热门话题
T
Tenable Blog
Hugging Face - Blog
Hugging Face - Blog
Google Online Security Blog
Google Online Security Blog
博客园 - Franky
P
Proofpoint News Feed
H
Hacker News: Front Page
P
Privacy & Cybersecurity Law Blog
月光博客
月光博客
P
Proofpoint News Feed
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
The GitHub Blog
The GitHub Blog
云风的 BLOG
云风的 BLOG
博客园_首页
www.infosecurity-magazine.com
www.infosecurity-magazine.com
C
CERT Recently Published Vulnerability Notes
Forbes - Security
Forbes - Security
I
InfoQ
Stack Overflow Blog
Stack Overflow Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Attack and Defense Labs
Attack and Defense Labs
N
News and Events Feed by Topic
博客园 - 叶小钗
T
Threat Research - Cisco Blogs
aimingoo的专栏
aimingoo的专栏
D
Darknet – Hacking Tools, Hacker News & Cyber Security
小众软件
小众软件
大猫的无限游戏
大猫的无限游戏
MongoDB | Blog
MongoDB | Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Hacker News - Newest:
Hacker News - Newest: "LLM"
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 司徒正美
O
OpenAI News
G
Google Developers Blog
Martin Fowler
Martin Fowler
罗磊的独立博客
S
SegmentFault 最新的问题
T
Tor Project blog
量子位

博客园 - 干炸小黄鱼

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生成器 springboot通用CURD Python PB级检索系统架构设计 rancher 在三台机器搭建k8s集群 python ssh clinet 数据库排序Null值字段靠后/靠前 常规web项目 docker-compose 例子 手搓一个验证码 使用itertools 中的groupby 对字典数组进行分组后排序 使用开源库 geoip2 获取某ip的经纬度地理信息 python中 apscheduler.schedulers.blocking.BlockingScheduler 定时执行任务 简单的python web项目的docker-compose.yml 示例 python和sliver交互 golang sliver二次开发自定义命令(格式乱后面再调) pydantic做参数校验 基于rancher部署k8s 地理位置相关基础数据 flask migrate时报错 Can't locate revision identified by '3d80e4c025df'
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
      两者的用法完全一样,但千万不能混用,因为线程和进程的内存空间是隔离的。