Python3 三种Queue的异同

一、Queue(队列)

Queue是python中的标准库,可以直接import 引用,队列默认遵循先进先出原则。

import queue
q = queue.Queue(10)
# 向队列中添加元素
q.put('yang')
q.put(4)
q.put(['yan', 'xing'])

# 从队列中取出元素,默认的队列是先进先出的
q.get()
# 'yang'
q.get()
# 4
q.get()
# ['yan', 'xing']

当一个队列为空的时候如果再用get取则会堵塞,所以取队列的时候一般是用到get_nowait()方法,这种方法在向一个空队列取值的时候会抛一个Empty异常,所以更常用的方法是先判断一个队列是否为空,如果不为空则取值。

队列中常用的方法
Queue.qsize() 返回队列的大小  
Queue.empty() 如果队列为空,返回True,反之False  
Queue.full() 如果队列满了,返回True,反之False 
Queue.get([block[, timeout]]) 获取队列,timeout等待时间  
Queue.get_nowait() 相当Queue.get(False) 

非阻塞 Queue.put(item) 写入队列,timeout等待时间

Queue.put_nowait(item) 相当Queue.put(item, False)

二、multiprocessing中的Queue

multiprocessing中的Queue是多进程间进行通信的消息队列。

from multiprocessing import Process,Queue
import os,time,random

#写数据进程执行的代码:
def write(p):
    for value in ['A','B','C']:
        print ('Write---Before Put value---Put %s to queue...' % value)
        p.put(value)
        print ('Write---After Put value')
        time.sleep(random.random())
        print ('Write---After sleep')

#读数据进程执行的代码:
def read(p):
    while True:
        print ('Read---Before get value')
        value = p.get(True)
        print ('Read---After get value---Get %s from queue.' % value)

if __name__ == '__main__':
    #父进程创建Queue,并传给各个子进程:
    p = Queue()
    pw = Process(target=write,args=(p,))
    pr = Process(target=read,args=(p,))
    #启动子进程pw,写入:
    pw.start()
    #启动子进程pr,读取:
    pr.start()
    #等待pw结束:
    pw.join()
    #pr进程里是死循环,无法等待其结束,只能强行终止:
    pr.terminate()

三、multiprocessing.Manager.Queue

如果把上面的代码改成下面的样子:

if __name__=='__main__':    
    # 父进程创建Queue,并传给各个子进程:
    q = Queue()
    p = Pool()
    pw = p.apply_async(write,args=(q,))    
    pr = p.apply_async(read,args=(q,))
    p.close()
    p.join()

本意是将会得到一个队列,将其作为参数传入进程池子里的每个子进程,但是却得到报错:RuntimeError: Queue objects should only be shared between processes through inheritance。

大意是:队列对象不能在父子进程间通信。如果想要在进程池中使用队列,则要使用multiprocessing的Mananger类:

if __name__=='__main__':
    manager = multiprocessing.Manager()
    # 父进程创建Queue,并传给各个子进程:
    q = manager.Queue()
    p = Pool()
    pw = p.apply_async(write,args=(q,))
    time.sleep(0.5)
    pr = p.apply_async(read,args=(q,))
    p.close()
    p.join()

这样这个队列对象就可以在父进程与子进程间通信,不用池则不需要Manager。

总结

queue.Queue 是进程内非阻塞队列

multiprocess.Queue 是跨进程通信队列

前者是各自进程私有, 后者是各子进程共有

Manager.Queue和 Queue,multiprocessing.Queue本质上没有太大关系,但它们有相同的方法。