进程之间的通信(multiprocess.Queue)
一、进程间通信
进程之间的数据是相互隔离的,例如
from multiprocessing import Process
def task():
global n # 声明全局变量
n = 999
print('子', n)
if __name__ == '__main__':
p = Process(target=task )
n=10
p.start()
print('主',n)
'''输出结果
主 10
子 999''' # 子进程中的数据并不会影响到父进程的数据
而想做到进程与进程之间的通信,就需要借助到第三方的媒介进行数据的交换获取等操作。
IPC(Inter-Process Communication)进程间通讯
二、队列
multiprocess.Queue
创建共享的进程队列,Queue是多进程安全队列,可以使用Queue实现多进程之间的数据传递。
Queue([maxsize]) #创建共享的进程队列
# maxsize是队列中允许的最大项数。如果省略此参数,则无大小限制
底层队列使用管道和锁定实现。
Queue方法
Queue([maxsize]):创建共享的进程队列。
Queue实例化之后q具有以下方法:
q.get([ block [ ,timeout ] ])
'''返回q中的一个项目。如果q为空,此方法将阻塞,直到队列中有项目可用为止。
block用于控制阻塞行为,默认为True. 如果设置为False,
将引发Queue.Empty异常(定义在Queue模块中)。
timeout是可选超时时间,用在阻塞模式中。
如果在制定的时间间隔内没有项目变为可用,将引发Queue.Empty异常。'''
from multiprocessing import Queue
if __name__ == '__main__':
q = Queue(3)
q.put('001')
q.put('002')
q.put('003')
print(q.get())
print(q.get())
print(q.get())
print(q.get(block=False))
# 将block设置为False就不会处在阻塞状态,一旦取不到值就会报异常。或者将timeout设定超时时间,超过这个时间取不到值也会报异常,不等待。
q.get_nowait() # 取值不会处在阻塞状态,一旦取不到值就会报异常
q.put_nowait() # 将值放入队列。如果队列已满,就会报异常
q.put(item [, block [,timeout ] ] )
'''将item放入队列。如果队列已满,此方法将阻塞至有空间可用为止。
block控制阻塞行为,默认为True。如果设置为False,将引发Queue.Empty异常(定义在Queue库模块中)。
timeout指定在阻塞模式中等待可用空间的时间长短。超时后将引发Queue.Full异常。'''
q.qsize()
'''返回队列中目前项目的正确数量。此函数的结果并不可靠,
因为在返回结果和在稍后程序中使用结果之间,队列中可能添加或删除了项目。
在某些系统上,此方法可能引发NotImplementedError异常。'''
q.empty()
'''判断q队列是否为空,空返回True,否则返回False。
如果其他进程或线程正在往队列中添加项目,结果是不可靠的。也就是说,
在返回和使用结果之间,队列中可能已经加入新的项目。'''
q.full() '''如果q已满,返回为True. 由于线程的存在,结果也可能是不可靠的(参考q.empty()方法)。'''
Queue解决进程间数据隔离问题
from multiprocessing import Queue, Process
import time
def task(q):
q.put(time.strftime('%Y-%m-%d %H:%M:%S'))
print('数据放完了')
if __name__ == '__main__':
q = Queue(3)
p = Process(target=task, args=(q,))
p.start()
res = q.get()
print('取到了%s' % res)
print('主')
'''输出结果
数据放完了
取到了2021-07-21 15:46:57
主'''
批量生产数据放入队列再批量获取结果
from multiprocessing import Queue, Process
import time
def q_put(q):
q.put(time.strftime('%Y-%m-%d %H:%M:%S'))
print('数据放完了')
def q_get(q):
print(q.get())
if __name__ == '__main__':
q = Queue(3)
p1 = Process(target=q_put, args=(q,))
p2 = Process(target=q_put, args=(q,))
p3 = Process(target=q_get, args=(q,))
p4 = Process(target=q_get, args=(q,))
p1.start()
p2.start()
p3.start()
p4.start()
生产者消费者模型
import os
import random
import time
from multiprocessing import Process, Queue,set_start_method # 针对mac用Queue出bug状况
def producer(queue, product):
for i in range(1, 11):
print('%s号流水线生产了第%s个%s' % (i, i, product))
time.sleep(random.random())
queue.put('第%s个%s' % (i, product))
def consumer(queue):
while True:
res = queue.get()
if not res: break # 发现none直接结束运行
print('%s消费者取走了%s' % (os.getpid(), res))
if __name__ == '__main__':
set_start_method('fork') # 针对mac用Queue出bug状况
q = Queue(3)
producer_p = Process(target=producer, args=(q, '大可乐'))
consumer_p = Process(target=consumer, args=(q,))
producer_p.start()
consumer_p.start()
producer_p.join() # 让子进程先运行完再添加标志
q.put(None)
多生产者 多消费者
# 生产者:
def producer(queue, food):
# 把数据全部放在Queue
for i in range(10):
data = "这个进程id:%s, 生产了%s个%s" % (os.getpid(), i, food)
print(data)
time.sleep(random.randint(1, 3))
# 放入数据
queue.put("第%s个%s" % (i, food))
def consumer(queue):
while True:
res = queue.get()
if not res:break
data = "这个进程id:%s, 吃了%s" % (os.getpid(), res)
print(data)
if __name__ == '__main__':
q = Queue(3)
p1 = Process(target=producer, args=(q, '面包'))
p2 = Process(target=producer, args=(q, '奶粉'))
p3 = Process(target=producer, args=(q, '冰淇淋'))
p1.start()
p2.start()
p3.start()
p4 = Process(target=consumer, args=(q,))
p5 = Process(target=consumer, args=(q,))
p4.start()
p5.start()
# time.sleep(1000)
# none放在这里是不行的,原因是主进程直接执行了put none, 消费者直接获取到None, 程序直接结束了
# p.join()
# q.put(None)
p1.join()
p2.join()
p3.join()
q.put(None)
q.put(None)
q.put(None)
多生产者 多消费者 消费者大于生产者
# 生产者:
def producer(queue, food):
# 把数据全部放在Queue
for i in range(10):
data = "这个进程id:%s, 生产了%s个%s" % (os.getpid(), i, food)
print(data)
time.sleep(random.randint(1, 3))
# 放入数据
queue.put("第%s个%s" % (i, food))
def consumer(queue, name):
while True:
try:
res = queue.get(timeout=5)
if not res:break
data = "这个消费者:%s, 吃了%s" % (name, res)
print(data)
except Exception as e:
print(e)
break
if __name__ == '__main__':
q = Queue(3)
p1 = Process(target=producer, args=(q, '面包'))
p2 = Process(target=producer, args=(q, '奶粉'))
p3 = Process(target=producer, args=(q, '冰淇淋'))
p1.start()
p2.start()
p3.start()
p4 = Process(target=consumer, args=(q, '许鹏'))
p5 = Process(target=consumer, args=(q, '勇哥'))
p6 = Process(target=consumer, args=(q, '勇哥2'))
p7 = Process(target=consumer, args=(q, '勇哥3'))
p4.start()
p5.start()
p6.start()
p7.start()
# time.sleep(1000)
# none放在这里是不行的,原因是主进程直接执行了put none, 消费者直接获取到None, 程序直接结束了
# p.join()
# q.put(None)
p1.join()
p2.join()
p3.join()
q.put(None)
q.put(None)
q.put(None)

浙公网安备 33010602011771号