如何制作Python';s多处理队列';s.empty()方法是否返回正确的值?还是其他选择?

如何制作Python';s多处理队列';s.empty()方法是否返回正确的值?还是其他选择?,python,multithreading,python-2.7,python-multiprocessing,Python,Multithreading,Python 2.7,Python Multiprocessing,我有一段代码,它使用了多进程模块中的队列类。我很困惑,队列实例的.empty()方法并没有像我期望的那样给我一个正确的值。这是我的代码: from time import sleep from multiprocessing import Queue, Lock foo = Queue() locker = Lock() with locker: # even with this, still True foo.put("bar") print(foo.empty()) # T

我有一段代码,它使用了
多进程
模块中的
队列
类。我很困惑,
队列
实例的
.empty()
方法并没有像我期望的那样给我一个正确的值。这是我的代码:

from time import sleep
from multiprocessing import Queue, Lock

foo = Queue()
locker = Lock()

with locker:  # even with this, still True
    foo.put("bar")

print(foo.empty())  # True, obviously not
print(foo.empty())  # True
print(foo.empty())  # True
print(foo.qsize())  # 1L
print(foo.empty())  # True
但是,如果我使用
time
中的
sleep
功能,则会导致执行时间延迟。它起作用了

from time import sleep
from multiprocessing import Queue, Lock

foo = Queue()
locker = Lock()

foo.put("bar")

sleep(0.01)

print(foo.empty())  # False
print(foo.empty())  # False
print(foo.empty())  # False
print(foo.qsize())  # 1L
print(foo.empty())  # False
我知道我的替代方法是
.qsize()>0
表达式,但我确信我这样做是错误的

我做错了什么

*编辑*

我现在明白了这是不可靠的,谢谢你@Mathias Ettinger。有没有干净的替代品?我需要知道hot,以便可靠地判断我的
队列是否为空。

根据,既不可靠,也不可靠

备选方案包括:

  • 读取通过
    队列的项目的确切数量

    AMT = 8
    for _ in range(AMT):
        queue.put('some stuff')
    
    for _ in range(AMT):
        print(queue.get())
    
    如果您事先知道总共需要处理多少项,或者每个线程将处理多少项,那么这将非常有用

  • 在监护人出现之前阅读物品:

    num_threads = 8
    guardian = 'STUFF DONE'
    
    while num_threads:
        item = queue.get()
        if item == guardian:
            num_threads -= 1
        else:
            process(item)
    
    如果每个线程都有可变的工作量(并且您事先不知道总工作量),但可以确定何时完成,那么这将非常有用


不幸的是,队列的复杂实现意味着
.empty()
.qsize()
检查不同的内容以做出判断。这意味着他们可能会有一段时间不同意,正如你所看到的

由于您的平台(即)支持
.qsize()
,因此您可以根据
.qsize()
重新实施
.empty()
检查,这将对您有效:

# mp.Queue() is a function, not a class, so we need to find the true class
# to subclass
import multiprocessing.queues

class XQueue(multiprocessing.queues.Queue):
    def empty(self):
        try:
            return self.qsize() == 0
        except NotImplementedError:  # OS X -- see qsize() implementation
            return super(XQueue, self).empty()
在后台,队列
.put()
是一个复杂的过程:队列将对象放置在缓冲区中并获取进程间信号量,而隐藏的守护进程线程负责排空缓冲区并将其内容序列化到管道。(然后,通过从该管道读取并释放进程间信号量,消费者
.get()
)因此,这就是为什么在您的示例中睡眠有效:在调用
.empty()
之前,守护进程线程有足够的时间将对象从内存缓冲区移动到I/O表示

另一方面,我发现这种行为令人惊讶:一个内部状态完全相同的队列可以对“是否有任何元素排队?”这一问题给出两种不同的答案(
qsize
会说“是”,而
empty
会说“否”。)


我想我明白这是怎么发生的。由于并非所有平台都支持
sem_getvalue()
,因此并非所有平台都可以实现
qsize
,但是
空的
可以通过轮询FIFO合理地实现。我希望
empty
能够在支持后者的平台上实现
qsize

什么都没有,无论是
empty()
full()
,还是
qsize()
都是哈哈,谢谢你的引用。有其他选择吗?不确定你想做什么,但也许a就是你想要的。我认为队列的一个真正接口是
put
get
<代码>空
用于近似统计。在处理节点中,我会使用
get(block=False)
立即查明队列是否为空或是否获取了一项工作。虽然这都是真的,但队列大小方法通常是“不可靠的”,因为信息一经获取就可能过时,而不是因为它们与实际队列状态不一致(这是OP注意到的)。此外,使用哨兵或队列中项目数量的先验知识是很好的技术,可以知道您何时完成了处理,但尚不清楚OP是否使用了
.empty()
您对NotImplementedError有何评论?我查看了文档,但没有任何相关内容。@用户,如果您按照我答案第二部分中的链接(关于
qsize()
未在每个平台上实现的链接),您将阅读该方法“…可能会在Mac OS X等Unix平台上引发
NotImplementedError
,其中未实现
sem_getvalue()
。“上面说
qsize
不可靠,就像
empty
full
一样。请您将我链接到您认为
qsize
立即被保证是正确的地方好吗?@MatthewMoisen,我重新考虑了这个答案的措辞——5年多后——并为清晰起见进行了编辑。谢谢。