进程间通信——生产者消费者模型
1、一些重要概念
***** 进程队列 : *** 队列是进程安全(进程间数据安全-多个进程不能同时操作同一个文件、数据库等)的!因为它自己带锁 *** 队列,实际上是基于'文件家族的socket服务'实现的!在运行队列的文件的同目录如果创建一个名为socket.py文件的话,执行时候会报错! ### 文件家族的socket服务实现的额IPC机制:队列、pipe(管道,没有带锁,有安全问题) ### pipe(管道) = 文件家族的socket服务 ### 队列 = pipe + 锁 1、进程之间通信(IPC) ## 进程间的通信:IPC —— inter process communication ## 多个进程之间的数据是隔离的 ## 进程之间的数据交互 ———— 可以通过:网络、文件来实现的————socket来实现 2、进程间通信的实现方式: ## 通过Python模块实现进程间的通信 ## 基于原生socket可以实现 ## 基于进程队列也可以实现 ***** ## 第三方的软件/工具来实现:基本都是基于网络的 ## memcache ## redis ## rabbitMQ ## kafka
2、基本的实现方法:子进程通过队列拿到主进程的值
# -*- coding:utf-8 -*- from multiprocessing import Process,Queue def task(q): # 在子进程中从队列中拿数据 g = q.get() print('子进程收到:',g) if __name__ == '__main__': # 实例化队列对象 q = Queue() # 开进程 process_task = Process(target=task,args=(q,)) process_task.start() # 在主进程中往队列添加一个值 q.put('wanghw')
结果:
子进程收到: wanghw
3、重要模型:生产者消费者模型 ——爬虫中用到:获取数据、处理数据(生产者消费者数量可变)
简单说明:
一:需要在生产者执行完之前阻塞主线程,因此每一个生产者都加join # 在生产者执行完之前必须阻塞主线程 # 逻辑上:producer生产完consumer可能还没有收完, # 因此得等producer生产完最后才能往队列里put跟消费者数量一样的None 二:最后为了结束程序 # 最后往队列中添加消费者数量的None
三:一个生产数据和消费数据的完整的流程解耦成为两个部分:生产跟消费
四:由于生产速度与消费速度不一致,所以需要我们调整生产者与消费者的个数来达到效率平衡
代码:
# -*- coding:utf-8 -*- import time import random from multiprocessing import Process,Queue def producer(name,q): for i in range(1,6): # 接收数据延迟 uniform方法必须有两个参数,这里表示0-1的任意小数 time.sleep(random.uniform(0,1)) data = 'data-%s'%i q.put(data) print('生产者 %s 生产了数据:%s'%(name,data)) def consumer(name,q): while 1: data = q.get() if data is None: print('\033[31;1m %s 消费完了 \033[0m'%name) break print('消费者 %s 收到数据:%s'%(name,data)) # 模拟处理数据延迟 random可以不带参数,这里表示0-1的任意小数 time.sleep(random.random()) if __name__ == '__main__': # 队列对象 q = Queue() # 三个生产者 # 四个消费者 pro_name = ['whw','naruto','sasuke'] con_name = ['aaa','bbb','ccc','ddd'] # 接收对象的列表 pro_lis = [] # 开子进程 for i in pro_name: p = Process(target=producer,args=(i,q)) p.start() # 千万别忘了 start!!! pro_lis.append(p) for i in con_name: p = Process(target=consumer,args=(i,q)) p.start() # 千万别忘了 start!!! # 需要等待生产者全部执行完 在生产者执行完之前必须阻塞主线程 # 逻辑上:producer生产完consumer可能还没有收完, # 因此得等producer生产完最后才能往队列里put跟消费者数量一样的None for i in pro_lis: i.join() # 最后根据消费者数量往队列中put None for i in range(len(con_name)): q.put(None)
结果: