下面的代码将三个数字放在一个队列中。然后,它尝试从队列中取回数字。但是它从来没有。如何从队列中获取数据?
import multiprocessing
queue = multiprocessing.Queue()
for i in range(3):
queue.put(i)
while not queue.empty():
print queue.get()
答案 0 :(得分:3)
在阅读@Martijn Pieters'之后,我最初删除了此答案,因为他更详细地描述了“为什么这不起作用”的内容。然后 我意识到,OP的示例中的用例不太适合
的规范发音标题“如何使用multiprocessing.Queue.get方法”。
那不是因为有 没有子进程用于演示,但是因为在实际应用中几乎没有预先填充队列,而是在读取之后才读取,但是读取 并在等待时间之间交错地进行写作。 Martijn展示的扩展演示代码在通常情况下不起作用,因为当入队不符合阅读要求时,while循环可能会中断得太早。因此,这里是重新加载的答案,它能够处理通常的交错提要和阅读方案:
不要依赖queue.empty检查同步。
将对象放入空队列后,在队列的empty()方法返回False且get_nowait()可以返回而不会引发queue.Empty之前,可能会有无穷的延迟。 ...
空()
如果队列为空,则返回True,否则返回False。由于多线程/多处理语义,这是不可靠的。 docs
从队列中使用for msg in iter(queue.get, sentinel):
到.get()
,您都可以通过传递哨兵值来打破循环... iter(callable, sentinel)?
from multiprocessing import Queue
SENTINEL = None
if __name__ == '__main__':
queue = Queue()
for i in [*range(3), SENTINEL]:
queue.put(i)
for msg in iter(queue.get, SENTINEL):
print(msg)
...或者如果需要非阻塞解决方案,请使用get_nowait()
并处理可能的queue.Empty
异常。
from multiprocessing import Queue
from queue import Empty
import time
SENTINEL = None
if __name__ == '__main__':
queue = Queue()
for i in [*range(3), SENTINEL]:
queue.put(i)
while True:
try:
msg = queue.get_nowait()
if msg == SENTINEL:
break
print(msg)
except Empty:
# do other stuff
time.sleep(0.1)
如果只有一个进程且该进程中只有一个线程正在读取队列,则还可以与以下命令交换最后一个代码段:
while True:
if not queue.empty(): # this is not an atomic operation ...
msg = queue.get() # ... thread could be interrupted in between
if msg == SENTINEL:
break
print(msg)
else:
# do other stuff
time.sleep(0.1)
由于线程可能会在检查if not queue.empty()
和queue.get()
之间丢弃GIL,因此这不适用于进程中的多线程队列读取。如果从队列中读取多个进程,则同样适用。
对于单一生产者/单一消费者的方案,使用multiprocessing.Pipe
代替multiprocessing.Queue
就足够了,并且性能更高。
答案 1 :(得分:2)
您的代码实际上可以正常工作,有时 。
那是因为队列不是立即也不为空。该实现更多地涉及支持多个进程之间的通信,因此涉及线程和管道,这些线程和管道导致empty
状态的持续时间比代码所允许的时间更长。
请参阅Pipes and Queues section中的注释:
将对象放入队列时,将对对象进行酸洗,然后后台线程将酸洗的数据刷新到基础管道。这会带来一些令人惊讶的后果,但不会造成任何实际困难-如果它们确实困扰您,那么您可以使用由经理创建的队列。
- 将对象放在空队列上后,在队列的
empty()
方法返回False
之前,可能会有无穷的延迟 [...]
(加粗强调)
如果您先添加一个循环以检查是否为空,那么您的代码将起作用:
queue = multiprocessing.Queue()
for i in range(3):
queue.put(i)
while queue.empty():
print 'queue is still empty'
while not queue.empty():
print queue.get()
运行上述命令时,大多数情况下'queue is still empty'
会出现一次。有时它根本不会出现,有时会被打印两次。
答案 2 :(得分:0)
在使用queue
之前检查get
:
import multiprocessing
queue = multiprocessing.Queue()
for i in range(3):
queue.put(i)
while not queue.empty():
if not queue.empty():
print queue.get()