multiprocessing 包中的 Queue 类是数据结构中 FIFO 队列的实现,包含下面三种实现:Queue -- 最通用的队列
SimpleQueue -- 最简单通用的队列实现
JoinableQueue -- 消息需要被确认的队列
Queue 和 JoinableQueue 以及所有 Queue 的子类,都依赖操作系统实现信号量,如果操作系统没有信号量的实现,则在实例化一个队列时,会抛出 ImportError
下面我们详细来介绍一下
Queue
Queue 是通过一个管道实现的 FIFO 进程间通信结构,它实现了标准库 queue.Queue 除 task_done 和 join 之外的所有方法
他是通过一个后台线程将用户放入或取出数据的请求传递给管道,受此异步实现的影响,所有判断队列中元素数量的方法,包括判断队列是否已满或是否为空的方法返回的数值可能都是不准确的
构造方法__init__(self, maxsize=0, *, ctx)
构造方法传入一个数字,用来标识队列的最大容量,默认的 0 表示不限容量
获取当前队列元素数 -- qsizeqsize()
返回队列当前元素数,很多类 Unix 环境中调用该方法会抛出 NotImplementedError,因为他们没有实现 sem_getvalue 方法
由于具体实现中,向队列中放入元素和信号量值的实际变化是异步的,所以这个方法的返回并不十分准确
插入元素
有两个方法可以向队列插入元素;put(obj, block=True, timeout=None)
put_nowait(obj)
put 方法将元素 obj 放入队列,同时可以指定这一过程是否需要阻塞等待以及超时,如果非阻塞且队列已满或超时后,会抛出 queue.Full
put_nowait 相当于 put(obj, False)
获取元素
与插入元素的两个方法一样,获取元素也有两个方法:get(block=True, timeout=None)
get_nowait()
get 方法从队列中取出一个元素,如果非阻塞且队列为空或超时后,会抛出 queue.Empty
get_nowait 相当于 get(False)
判断队列是否为空 -- emptyempty()
返回 bool 值,队列为空则返回 True
判断队列是否已满 -- fullfull()
返回 bool 值,队列已满则返回 True
关闭队列 -- closeclose()
close() 方法一旦调用,则队列不允许再放入任何数据,当所有数据都被刷入管道,后台线程就会退出
同步等待后台线程刷新数据 -- join_threadjoin_thread()
等待后台进程刷新数据,只有调用过 close 方法以后才可以调用该方法
调用该方法后,进程会一直阻塞,直到所有数据都被刷入队列中的管道,队列的后台线程退出
取消等待 -- cancel_join_threadcancel_join_thread()
默认的,进程在向队列插入数据后退出,都会自动等待后台线程刷新 pipe
在此之前,通过 cancel_join_thread 可以改变这一默认的行为,即使进程主动调用 join_thread 方法,也会立即返回,作为代价,数据可能并没有被真的写入管道中从而导致数据的丢失
SimpleQueue
这是一个简单而通用的队列实现,他可以被认为是一个加锁的管道,与另两个 multiprocessing 提供的队列不同,他可以在没有实现信号量的操作系统中使用
他实现的方法非常少,只有下面三个:empty() -- 返回 bool 值表示该队列是否为空
get() -- 获取一个元素
put(item) -- 将一个元素放入队列
JoinableQueue
JoinableQueue 是 Queue 的一个子类,他与 Queue 的区别在于它实现了 task_done 和 join 方法
构造方法__init__(self, maxsize=0, *, ctx)
与 Queue 一样,JoinableQueue 的构造方法也支持传入一个数值,用于指定队列的最大容量,为 0 则不限制容量
确认消息 -- task_donetask_done()
task_done 方法标识最近一次 get 得到的元素已经被处理,则下次 get 方法将返回新数据
等待数据被确认 -- joinjoin()
阻塞,直到队列中所有元素都被接收且被 task_done 方法标识为处理完毕
示例
我们将上面的管道的例子改为使用队列:
from multiprocessing import Process, Queue
def f(q):
q.put([42, None, 'hello'])
if __name__ == '__main__':
q = Queue()
p = Process(target=f, args=(q,))
p.start()
print(q.get())
p.join()
打印出了:[42, None, 'hello']