
























在 Python 的多线程编程中,threading.Condition(条件变量)是一个非常强大的线程同步工具。
你可以把它通俗地理解为 “高级版的 Event” 或者 “带锁的 Event”。
它最经典的应用场景就是生产者-消费者模型(例如:缓冲区满了生产者要等,缓冲区空了消费者要等)。
Condition 对象内部自带一把锁(默认是 RLock),它的所有核心操作都必须在这把锁的保护下进行(通常使用 with 语句):
| 方法 | 作用 | 通俗解释 |
|---|---|---|
acquire() / release() |
获取/释放内部的锁 | 进出门要记得开关门(通常用 with 代替) |
wait(timeout=None) |
释放锁并阻塞等待 | “我先让出资源,等条件满足了再叫醒我” |
notify(n=1) |
唤醒 1个 等待的线程 | “条件变了,叫醒其中 1 个人来看看” |
notify_all() |
唤醒 所有 等待的线程 | “条件变了,大家都起来看看” |
下面通过一个经典的案例,展示 Condition 是如何协调两个线程对同一个共享资源(列表缓冲区)进行操作的:
import threading
import time
import random
# 共享资源(缓冲区)
buffer = []
MAX_SIZE = 5
# 创建 Condition 对象
condition = threading.Condition()
def producer():
"""生产者:不断生产数据放入缓冲区"""
while True:
with condition: # 自动获取锁
# 如果缓冲区满了,就等待消费者消费
while len(buffer) >= MAX_SIZE:
print("【生产者】缓冲区已满,等待消费者消费...")
condition.wait() # 释放锁,并阻塞等待
# 生产数据
item = random.randint(1, 100)
buffer.append(item)
print(f"【生产者】生产了数据: {item}, 当前库存: {len(buffer)}")
# 生产完毕,通知等待的消费者
condition.notify()
time.sleep(random.uniform(0.1, 0.5)) # 模拟生产耗时
def consumer():
"""消费者:不断从缓冲区取出数据"""
while True:
with condition: # 自动获取锁
# 如果缓冲区空了,就等待生产者生产
while len(buffer) == 0:
print("【消费者】缓冲区已空,等待生产者生产...")
condition.wait() # 释放锁,并阻塞等待
# 消费数据
item = buffer.pop(0)
print(f"【消费者】消费了数据: {item}, 当前库存: {len(buffer)}")
# 消费完毕,通知等待的生产者
condition.notify()
time.sleep(random.uniform(0.1, 0.5)) # 模拟消费耗时
# 启动线程
t1 = threading.Thread(target=producer)
t2 = threading.Thread(target=consumer)
t1.start()
t2.start()
在使用 Condition 时,有几个极其重要的细节需要注意,否则很容易出现死锁或逻辑错误:
while 循环检查条件:wait() 时,一定要写成 while not condition_met: wait(),而不能用 if。因为线程可能会被“虚假唤醒”(即没有被 notify 却自己醒了),用 while 可以在醒来后再次确认条件是否真的满足。wait()、notify() 和 notify_all() 都必须在 with condition: 代码块(或者手动 acquire() 之后)调用,否则会直接抛出 RuntimeError 异常。notify() 不会释放锁:notify() 只是把等待的线程叫醒,但不会释放当前的锁。被叫醒的线程必须等到你退出 with 代码块(锁被释放)后,才能重新获取锁并继续执行。wait() 会自动释放锁:wait() 时,它会自动释放锁,这样其他线程才有机会获取锁并修改共享数据。简单来说,需要多个线程之间进行复杂的“你做完我再做”、“没资源我就等,有资源你就叫醒我”的协作时,Condition 就是最合适的工具。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。