「这是我参与2022首次更文挑战的第14天,活动详情查看:2022首次更文挑战」。
在 《【Python】多进程-进程间通信之队列》 中,讲解了如何通过队列实现各进程之间的通信,本文将继续介绍如何使用管道进行多线程间的通信。
管道
管道与队列显示,对于单向的管道,在管道的一端放入元素,在另一端取出元素。而对于双向的管道,则可以在管道的两端存取元素。
创建一个管道
使用 multiprocessing.Pipe(duplex= True)
可一创建一个管道,这个管道默认是一个双向管道(duplex= True
),其返回两个 multiprocessing.connection.Connection
对象,分别表示这个管道的两端。
使用管道
有了管道之后,就可以通过管道发送和接受对象了。
发送对象有两种方法: send(obj)
和 send_bytes(buf, offset=0, size=None)
。第一个方法发送一个对象,第二个方法则从一个 bytes-like object
对象中取出 size
大小的数据,并作为一条完整消息发送。需要注意的是,如果对象或buffer
过大(接近32MB,取决于操作系统),有可能导致 ValueError
的异常。
对应的接收方法有三个: recv()
、recv_bytes(maxlength=None)
和 recv_bytes_into(buffer, offset=0)
。如果管道为空,则调用接收方法时会被阻塞。如果管道的另一端被关闭了,则会抛出 EOFError
异常。
除了发送和接收,还有管道的主要方法还有:
close()
:关闭连接poll(timeout=0.0)
:返回管道中是否有可以读取的数据,如果没有可读数据,timeout
指定了最多等待(阻塞)多长时间
代码
最后,通过代码演示一下多进程通过管道进行通信。
代码实现了一个经典的生产者-消费者问题:一个厨师生产蛋糕,三个顾客嗷嗷待哺:
import multiprocessing
import multiprocessing
import time
import random
class cake:
def __init__(self, time):
self.productionTime = time
def eat(self):
print("Eat a cake product at ", self.productionTime)
def cook(conn):
for _ in range(6):
conn.send(cake(time.time()))
time.sleep(random.random())
conn.close()
def customer(conn):
for _ in range(2):
cake = conn.recv()
cake.eat()
time.sleep(random.random() * 5)
if __name__ == "__main__":
conn1, conn2 = multiprocessing.Pipe()
p1 = multiprocessing.Process(target= cook, args=(conn1, ))
p2 = multiprocessing.Process(target= customer, args=(conn2, ))
p3 = multiprocessing.Process(target= customer, args=(conn2, ))
p4 = multiprocessing.Process(target= customer, args=(conn2, ))
p1.start()
p2.start()
p3.start()
p4.start()