使用Condition控制线程协作避免资源竞争和死锁
- 资源竞争与死锁问题:在高并发后端网络服务中,多个线程对共享资源进行读写操作时,可能出现资源竞争,比如多个线程同时写导致数据不一致;死锁则可能由于线程互相等待对方释放资源而发生。
- Condition基本原理:Condition是基于锁(Lock)实现的,通过允许线程等待特定条件满足后再执行,来协调线程间的操作。
- 使用步骤
import threading
lock = threading.Lock()
condition = threading.Condition(lock)
- **线程读操作示例**:
def read_data():
with lock:
while not data_available: # data_available 是共享资源是否可用的标志
condition.wait() # 等待条件满足,线程进入等待状态并释放锁
# 此时共享资源可用,进行读操作
data = shared_resource
- **线程写操作示例**:
def write_data(new_data):
with lock:
# 修改共享资源
shared_resource = new_data
data_available = True
condition.notify_all() # 通知所有等待的线程,共享资源已更新
- 避免死锁:
- 所有线程获取锁和Condition的顺序要一致。例如,在上述代码中,无论是读线程还是写线程,都先通过
with lock
获取锁,再使用Condition相关操作。
- 避免嵌套锁,尽量简化锁的层次结构。如果确实需要嵌套锁,要确保获取锁的顺序是可预测的。
Condition与Event对比
- 优势
- 更细粒度控制:Condition基于锁,可以在持有锁的情况下进行等待和唤醒操作,能够针对不同条件进行更细粒度的线程控制。而Event是一种简单的通知机制,所有等待该Event的线程会同时被唤醒,无法区分不同条件。
- 灵活的唤醒策略:Condition可以使用
notify()
唤醒单个等待线程,notify_all()
唤醒所有等待线程,根据具体业务需求选择合适策略。Event只能唤醒所有等待线程。
- 适用场景
- Condition适用场景:适用于复杂业务逻辑,多个线程需要基于不同条件进行协作的场景,如生产者 - 消费者模型中,消费者线程可能因为不同产品类型等待,生产者根据不同产品生产完成后通知对应的消费者。
- Event适用场景:适用于简单场景,只需简单通知所有线程某个事件发生,无需区分条件,如服务器启动完成后通知所有等待初始化完成的线程开始工作。