Python学习之路-----Queue

进程间通信

多进程实现了并发行为但却带来一个问题,进程间通信!在实际的生活中这种例子很常见,如微信聊天视频。如果进程间不能通信那么每个应用程序就失去了存在的意义。在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创建的队列。

发布了76 篇原创文章 · 获赞 21 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/shen_chengfeng/article/details/102656630