python高级编程-condition

在 Python 的多线程编程中,threading.Condition(条件变量)是一个非常强大的线程同步工具。

你可以把它通俗地理解为 “高级版的 Event” 或者 “带锁的 Event”

  • Event 只能控制线程的“走”与“停”(红灯/绿灯)。
  • Condition 则更精细,它允许线程在等待时释放锁,让其他线程有机会修改共享数据,并在条件满足时被精准唤醒

它最经典的应用场景就是生产者-消费者模型(例如:缓冲区满了生产者要等,缓冲区空了消费者要等)。

💡 Condition 的核心方法

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 时,有几个极其重要的细节需要注意,否则很容易出现死锁或逻辑错误:

  1. 必须使用 while 循环检查条件
    调用 wait() 时,一定要写成 while not condition_met: wait(),而不能用 if。因为线程可能会被“虚假唤醒”(即没有被 notify 却自己醒了),用 while 可以在醒来后再次确认条件是否真的满足。
  2. 必须在持有锁的情况下调用
    wait()notify()notify_all() 都必须在 with condition: 代码块(或者手动 acquire() 之后)调用,否则会直接抛出 RuntimeError 异常。
  3. notify() 不会释放锁
    调用 notify() 只是把等待的线程叫醒,但不会释放当前的锁。被叫醒的线程必须等到你退出 with 代码块(锁被释放)后,才能重新获取锁并继续执行。
  4. wait() 会自动释放锁
    这是 Condition 最精妙的地方。当线程执行到 wait() 时,它会自动释放锁,这样其他线程才有机会获取锁并修改共享数据。

简单来说,需要多个线程之间进行复杂的“你做完我再做”、“没资源我就等,有资源你就叫醒我”的协作时,Condition 就是最合适的工具。

posted @ 2026-05-09 10:17  干炸小黄鱼  阅读(17)  评论(0)    收藏  举报