如何制作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年多后——并为清晰起见进行了编辑。谢谢。