本文共 2659 字,大约阅读时间需要 8 分钟。
生产者消费者模型是处理数据生产与消费的经典模式,适用于分布式系统中的数据处理。生产者负责生产数据,消费者负责消费数据。这种模型通过队列进行通信,保证了数据的有序性和安全性。以下是使用Python的multiprocessing模块实现的生产者消费者模型示例:
import timeimport randomfrom multiprocessing import Process, Queuedef consumer(q): while True: obj = q.get() print(f'消费了一个数据{obj}') time.sleep(random.randint(1, 3))if __name__ == "__main__": q = Queue() Process(target=consumer, args=(q,)).start() for i in range(10): time.sleep(random.randint(1, 5)) q.put(f'food{i}') print(f'生产了一个数据food{i}') 运行上述代码会观察到生产者和消费者交替工作的现象,随着时间的推移,队列中的数据会被逐一消费完毕。
在上述模型中,q.get()是阻塞操作,直到队列中有数据被放入为止。这保证了生产者和消费者能够高效地进行数据交换。
管道(Pipe)是多进程间通信的基础设施,通过一个双向通道实现数据的传递。以下是一个简单的管道通信示例:
from multiprocessing import Pipe, Processdef consumer(lp, rp): lp.close() while True: try: print(rp.recv()) except EOFError: breakif __name__ == "__main__": lp, rp = Pipe() Process(target=consumer, args=(lp, rp)).start() Process(target=consumer, args=(lp, rp)).start() Process(target=consumer, args=(lp, rp)).start() Process(target=consumer, args=(lp, rp)).start() Process(target=consumer, args=(lp, rp)).start() rp.close() for i in range(500): lp.send(f'food{i}') lp.close() 运行上述代码会发现,主进程将500个“food”对象发送到管道中,随后所有进程都会退出,完成任务。
在多进程环境下,共享数据需要谨慎处理,否则可能导致数据竞争和不一致性。普通模式下,直接使用共享数据可能会出现问题:
from multiprocessing import Manager, Process, Lockdef work(d, lock): with lock: d['count'] -= 1if __name__ == "__main__": lock = Lock() m = Manager() dic = m.dict({'count': 100}) p_l = [] for i in range(100): p = Process(target=work, args=(dic, lock)) p_l.append(p) p.start() for p in p_l: p.join() print(dic) 运行上述代码后,dic中的count会减少到0,表明所有进程都完成了工作。
为了避免数据竞争,可以使用上下文管理器:
from multiprocessing import Manager, Process, Lockdef work(d, lock): with lock: d['count'] -= 1if __name__ == "__main__": with Manager() as m: dic = m.dict({'count': 100}) p_l = [] for i in range(100): p = Process(target=work, args=(dic, lock)) p_l.append(p) p.start() for p in p_l: p.join() print(dic) 与普通模式结果一致,dic中的count减少到0。
进程池提供了更高效的任务调度方式,适用于需要多进程执行的任务。以下是一个使用进程池的示例:
import osimport timedef wahaha(num): print(f'子{os.getpid()}') return num ** numdef call(argv): print(f'主{os.getpid()}') print(argv)if __name__ == "__main__": print('主', os.getpid()) p = Pool(5) p.apply_async(func=wahaha, args=(50,), callback=call) p.close() p.join() 运行上述代码会看到主进程和子进程交替输出信息,最终所有任务完成后,进程池关闭。
转载地址:http://djlfk.baihongyu.com/