0%

Python进程通信

#9 Python进程通信

有时候需求并不是简简单单的产生多个进程即可,而是会对进程提出更高的要求,比如进程1完成进程2才能启动、进程3工作时进程4不可以工作等要求,这就涉及到了进程的通信,尤其体现在进程的同步和互斥,本小节博文将继续深入Python进程,Here we go!

队列

进程之间无法直接通信,必须通过“中间人”传递消息,从而间接的达到通信目的。能作为“中间人”身份的有两种:队列和管道。

队列是一种数据结构,特点是“先进先出(FIFO)”,与栈刚好相反,队列就是一种排队模型,谁先来谁先享受服务。

1
2
3
4
5
6
7
8
9
--------------------------------     ______________
-------------------------------- < 卖老婆咯 >
mmmmm mm mmmm mmmm mmm --------------
# m"# " "# " "# # \ ^__^
""""mm #" # mmm" m" # \ (oo)\_______
# #mmm#m "# m" # (__)\ )\/\
"mmm#" # "mmm#" m#mmmm mm#mm ||----w |
-------------------------------- || ||
--------------------------------

队列multiprecessing.Queue

注意这里的队列模块是multiprocessing里的Queue,只有这个才能用于进程的通信,自带的系统模块Queue不能实现进程的通信。

multiprocessing.Queue类常用的方法有:

方法 解释
put(obj) 将obj放入队列
get(obj) 将obj从队列取出
empty() 判断队列是否为空
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/env python
#-*- coding:UTF-8 -*-


from multiprocessing import Queue


if __name__ == '__main__':
queue = Queue() # 创建一个队列

queue.put('馒头') # 先放入馒头
queue.put('包子') # 再放入包子

print('第一次取出:', queue.get())
print('第二次取出:', queue.get())


运行结果:
第一次取出: 馒头
第二次取出: 包子

进程通过Queue通信

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#!/usr/bin/env python
#-*- coding:UTF-8 -*-
# 简单的生产者消费者模型

import multiprocessing
from multiprocessing import Process, Queue

def produce(queue, name):
for i in range(10): # 生产10个产品
queue.put(name)
print(multiprocessing.current_process(), '生产了一个', name, ',成功放入队列')

def consume(queue):
try:
while True:
name = queue.get(timeout=2) # 从队列中取出产品,如果超过2秒没有取到产品,则抛出队列空异常
print(multiprocessing.current_process(), '消费了一个', name, ',成功从队列取出')
except Exception as e:
print('队列为空,无法消费')


if __name__ == '__main__':
queue = Queue() # 创建一个队列

p1 = Process(target=produce, args=(queue, '包子')) # 包子生产商
p2 = Process(target=produce, args=(queue, '馒头')) # 馒头生产商

p3 = Process(target=consume, args=(queue,)) # 消费者



p1.start()
p2.start()
p3.start()

管道

管道Pipe是另一种进程通信中介,管道拥有两个口,通常情况下2个进程分别位于管道的两端,管道默认为全双工工作,也就是进程既可以发送数据也可以接受数据。 #### 管道multiprocessing.Pipe multiprocessing.Pipe类常用的方法有:

方法 解释
send(obj) 向管道另一端发送一个obj
recv() 接受从管道另一端发过来的数据
close() 关闭连接
poll() 返回连接中是否还有数据可以读取
send_bytes(buffer) 发送字节数据
recv_bytes() 接受字节数据
recv_bytes_into(buffer) 接受字节数据到buffer中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/usr/bin/env python
#-*- coding:UTF-8 -*-


from multiprocessing import Pipe


if __name__ == '__main__':
conn1, conn2 = Pipe()

conn1.send('Hello~') # conn1向管道发送数据Hello~
print(conn2.recv()) # conn2从管道接受数据Hello~

print('分割线'.center(20, '-'))

conn2.send('Hi~~') # conn2向管道发送数据Hi~~
print(conn1.recv()) # conn1从管道接受数据Hi~~


运行结果:
Hello~
--------分割线---------
Hi~~

小结

Python进程通信涉及到很多编程思想,利用Queue实现生产者消费者模型,平衡了生产者和消费着的处理能力。