进程间通信
多进程实现了并发行为但却带来一个问题,进程间通信!在实际的生活中这种例子很常见,如微信聊天视频。如果进程间不能通信那么每个应用程序就失去了存在的意义。在linux中进程间通信的方式有:管道(有名管道、无名管道)、共享内存、消息队列、socket等。python的进程间通信最常用的是Queue,即队列。队列的特性是先进先出,与之相反的是先进后出,即栈。
Queue的基本使用
# coding=utf-8
from multiprocessing import Queue
q = Queue(3) # 初始化一个Queue对象,最多可接收三条put消息
print(q.qsize())
print(q.full())
print()
q.put("消息1")
q.put("消息2")
print('把消息1、消息2放入队列中')
print(q.qsize())
print(q.full()) # False
print()
q.put("消息3")
print(q.full()) # True
# 因为消息列队已满下面的try都会抛出异常,第一个try会等待2秒后再抛出异常,第二个Try会立刻抛出异常
try:
q.put("消息4", True, 2)
except:
print("消息列队已满,现有消息数量:%s" % q.qsize())
try:
q.put_nowait("消息4")
except:
print("消息列队已满,现有消息数量:%s" % q.qsize())
# 推荐的方式,先判断消息列队是否已满,再写入
if not q.full():
q.put_nowait("消息4")
# 读取消息时,先判断消息列队是否为空,再读取
if not q.empty():
for i in range(q.qsize()):
print(q.get_nowait())
#print(q.get())
print('\n尝试再取一次消息:')
print(q.get_nowait())#会出错
结果:
0
False
把消息1、消息2放入队列中
2
False
True
消息列队已满,现有消息数量:3
消息列队已满,现有消息数量:3
消息1
消息2
消息3
尝试再取一次消息:
Traceback (most recent call last):
File "E:/sourceInsightPro/python_code/16点14分/queuetest.py", line 39, in <module>
print(q.get_nowait())
File "E:\soft\python3\lib\multiprocessing\queues.py", line 126, in get_nowait
return self.get(False)
File "E:\soft\python3\lib\multiprocessing\queues.py", line 107, in get
raise Empty
_queue.Empty
Queue(3)创建了一个可以容纳三条消息的队列,qsize()获得队列中当前消息的数量,full()判断当前消息队列是否已经满了,put()和put_nowait()是把消息放入消息队列中,通过以上执行的动态结果可以看出二者的区别是put默认是阻塞的,并且第三个参数是等待时间,如果已经超时但是消息队列已经满了就不再等待,继续向下执行。get()和get_nowait()是从消息队列中取出消息。如果消息队列中已经取完了所有的消息还尝试再取的话就会出错。因此在取之前一定要判断当前消息队列是否为空。另外通过消息输出的先后顺序可能看出Queue是先进先出的原则。
通信实例Process
#coding=utf-8
from multiprocessing import Process,Queue
import time
def p_w(q):
for i in range(5):
time.sleep(1)
str1 = '消息' + str(i)
print('p_w,put msg:%s to queue'% str1)
q.put(str1)
def p_r(q):
while True:
time.sleep(1)
if not q.empty():
print(q.get())
else:
break
if __name__ == '__main__':
print('-----------main begin!---------')
q = Queue(5)
p1 = Process(target=p_w,args=(q,));
p2 = Process(target=p_r, args=(q,));
p1.start()
p1.join()
p2.start()
p2.join()
print('-----------main over!---------')
结果:
-----------main begin!---------
p_w,put msg:消息0 to queue
p_w,put msg:消息1 to queue
p_w,put msg:消息2 to queue
p_w,put msg:消息3 to queue
p_w,put msg:消息4 to queue
消息0
消息1
消息2
消息3
消息4
-----------main over!---------
这个例子演示的是一个进程往队列中写消息,一个从队列中读取消息。在主进程中不好的逻辑是:先让进程p1执行完后才开始进程p2,这样就失去了两个进程间实时同步的效果。因此在实际开发中应该是两个进程前后开启,信息尽量同步交互。就这个例子来说如果改成进程先后启动,p2可能读不到消息,因为p2的逻辑有点缺陷。希望大家能改改,提供一下新的思路。
通信实例Pool
使用Queue创建的消息队列只能满足Process进程间通信的例子,不能满足进程池间通信的情况。应该使用如下的方式:
#coding=utf-8
from multiprocessing import Manager,Queue,Pool
import time
def p_r(q):
time.sleep(1)
for i in range(q.qsize()):
print(q.get())
def p_w(q):
for i in range(5):
str1 = '消息' + str(i);
print('put %s to queue' % str1 )
q.put(str1)
if __name__ == '__main__':
print('==========main begin==========')
pool = Pool()
q = Manager().Queue()
pool.apply_async(p_w,(q,))
pool.apply_async(p_r, (q,))
pool.close()
pool.join()
print('==========main end==========')
结果:
==========main begin==========
put 消息0 to queue
put 消息1 to queue
put 消息2 to queue
put 消息3 to queue
put 消息4 to queue
消息0
消息1
消息2
消息3
消息4
==========main end==========
重点就是使用Manger.Queue创建的队列。