管道:
基于socket 和pickle实现的
管道是队列的底层
数据不安全
源码对管道的解释:
The Pipe() function returns a pair of connection objects connected by a pipe which by default is duplex (two-way)
该函数返回一对连接用管道的默认两端的特征
Each connection object has ***send()*** and ***recv()*** methods
管道可以分为双工管道和单向管道。管道也是用队列的原理实现的。双工就是两边都可以存取信息。
管道也可以实现进程间的通信。但是进程间数据不安全。且存取数据复杂,
队列是基于管道实现的。管道是基于socket实现的。队列是管道的一种升级,基于管道中很多弊端形成了队列。
队列在进程中数据是安全的。因为两个队列不会同时取队列中的一个数据。也不会往同一个地方放数据。队列会严格的维持持续,不会有不安全的情况发送。
管道在进程之间数据不安全的。虽然管道也能实现IPC通信, 队列是管道加锁实现的,就是因为每次取数据和放数据时都添加了锁。所以永远不可能有两个进程同时修改一个队列了,
例1:
管道对象返回值
from multiprocessing import Pipe,Process
pipe = Pipe()
print(pipe)
运行结果
(<multiprocessing.connection.PipeConnection object at 0x0000019B2245A4E0>, <multiprocessing.connection.PipeConnection object at 0x0000019B2245A2E8>) # 结果是管道的两端地址。可以元祖第一个收,第二个发
在一个进程中收发
from multiprocessing import Pipe
left, right = Pipe() # 一个管道有两端
left.send(12345) # 由于内部时基于socket和pickle实现的,所以不用传byte类型的,传任何数据类型都可以 # 左边传
print(right.recv()) # 右边收
运行结果
12345
例2:
用pipe写一个生产者消费者模型
pipe的端口管理不会随着某个进程的关闭就关闭,而是交给操作系统计数器做的。操作系统来管理进程对这些端口的使用。只有所有的进程都关闭了后才能感知到。如有两个进程,分别有两个端口,操作系统此时要管理4个端口。每关闭一个就-1,直到端口数目为剩1时。recv行为就报错。所有给我发信息的都关掉了,这时还recv就报错。所以必须手动把所有端口都关闭,归还操作系统资源。来触发EOFError,来结束某一个消费着的行为。否则即使所有代码都执行完,还是会在recv时阻塞。等着接收消息,因为不知道你还会不会给我发消息。
from multiprocessing import Pipe,Process
def consumer(left, right):
left.close()
while True:
try:
print(right.recv())
except EOFError:
break
if __name__ == '__main__':
left, right = Pipe()
Process(target=consumer, args=(left, right)).start()
right.close()
for i in range(10):
left.send('%s' % i)
left.close()
运行结果
0
1
2
3
4
5
6
7
8
9
例3:
from multiprocessing import Process, Pipe
def f(conn):
conn.send([12, {'name': 'laura'}, 'hello'])
response = conn.recv()
print('response', response) # response hello son!
conn.close()
print('q_ID2:', id(conn)) # q_ID2: 1576863392992
if __name__ == '__main__':
parent_conn, child_conn = Pipe()
print('q_ID1: ', id(child_conn)) # q_ID1: 1745512879552
p = Process(target=f, args=(child_conn,))
p.start()
print(parent_conn.recv()) # [12, {'name': 'laura'}, 'hello']
parent_conn.send('hello son!')
p.join()
运行结果
q_ID1: 1745512879552
[12, {'name': 'laura'}, 'hello']
response hello son!
q_ID2: 1576863392992