MST

星途 面试题库

面试题:Python threading模块中Event与Condition的区别及应用场景

详细阐述Python threading模块中Event和Condition对象的工作原理,在什么情况下应该优先选择使用Event,什么情况下使用Condition更合适,并各举一个实际应用场景的代码示例。
11.4万 热度难度
编程语言Python

知识考点

AI 面试

面试题答案

一键面试

Event对象工作原理

Event对象是线程间通信的简单机制,它包含一个内部标志。线程可以通过set()方法将这个标志设为True,通过clear()方法将其设为False。其他线程可以调用wait()方法来阻塞,直到标志变为True。当Event对象的标志为True时,调用wait()方法的线程将立即继续执行,而不会阻塞。

Condition对象工作原理

Condition对象用于更复杂的线程同步场景。它结合了锁(Lock)和条件变量的功能。线程可以通过acquire()方法获取锁,通过release()方法释放锁。Condition对象提供了wait()notify()notify_all()方法。当一个线程调用wait()时,它会释放锁并进入等待状态,直到其他线程调用notify()notify_all()唤醒它。唤醒后,线程会重新获取锁才继续执行。

优先选择Event的情况

当需要简单的线程间信号通知,即一个线程需要告知其他线程某个事件已经发生,不需要复杂的同步逻辑时,优先选择Event。例如,一个线程负责监控文件是否被创建,当文件创建后通知其他线程进行处理。

Event应用场景代码示例

import threading
import time


def monitor_file(event):
    print('开始监控文件')
    time.sleep(5)
    print('文件已创建')
    event.set()


def process_file(event):
    print('等待文件创建')
    event.wait()
    print('开始处理文件')


if __name__ == '__main__':
    event = threading.Event()
    t1 = threading.Thread(target=monitor_file, args=(event,))
    t2 = threading.Thread(target=process_file, args=(event,))
    t1.start()
    t2.start()
    t1.join()
    t2.join()

优先选择Condition的情况

当线程间需要更复杂的同步,比如多个线程依赖不同条件进行协作,或者需要在等待条件时执行一些清理操作时,使用Condition更合适。例如,生产者 - 消费者模型中,消费者需要等待生产者生产出产品后才能消费,并且可能存在多个消费者和生产者。

Condition应用场景代码示例

import threading
import time


class Queue:
    def __init__(self):
        self.items = []
        self.max_size = 5
        self.cond = threading.Condition()

    def put(self, item):
        with self.cond:
            while len(self.items) >= self.max_size:
                print('队列已满,生产者等待')
                self.cond.wait()
            self.items.append(item)
            print(f'生产者生产: {item}')
            self.cond.notify()

    def get(self):
        with self.cond:
            while not self.items:
                print('队列为空,消费者等待')
                self.cond.wait()
            item = self.items.pop(0)
            print(f'消费者消费: {item}')
            self.cond.notify()
            return item


def producer(queue):
    for i in range(10):
        queue.put(i)
        time.sleep(1)


def consumer(queue):
    for _ in range(10):
        queue.get()
        time.sleep(1)


if __name__ == '__main__':
    q = Queue()
    t1 = threading.Thread(target=producer, args=(q,))
    t2 = threading.Thread(target=consumer, args=(q,))
    t1.start()
    t2.start()
    t1.join()
    t2.join()