繁体   English   中英

如何使用multiprocessing.Queue.get方法?

[英]How to use multiprocessing.Queue.get method?

下面的代码将三个数字放在一个队列中。 然后,它尝试从队列中取回数字。 但是它永远不会。 如何从队列中获取数据?

import multiprocessing

queue = multiprocessing.Queue()

for i in range(3):
    queue.put(i)

while not queue.empty():
    print queue.get()

在阅读@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):使用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足够了,并且性能更高。

您的代码实际上有时有效

那是因为队列不是立即不为空。 该实现涉及更多的内容以支持多个进程之间的通信,因此涉及线程和管道,这些线程和管道导致empty状态的持续时间比代码所允许的时间更长。

请参阅“ 管道和队列”部分中的注释:

将对象放入队列时,将对对象进行酸洗,然后后台线程将酸洗的数据刷新到基础管道。 这带来了一些令人惊讶的后果,但不会造成任何实际困难-如果它们确实困扰您,那么您可以使用由经理创建的队列。

  1. 将对象放在空队列上之后,队列的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'出现一次。 有时它根本没有出现,有时它会被打印两次。

使用get之前检查queue

import multiprocessing

queue = multiprocessing.Queue()

for i in range(3):
    queue.put(i)

while not queue.empty():
    if not queue.empty():
        print queue.get()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM