为什么Python的队列在qsize()方法中返回近似值?

14
在qsize()的文档中说:返回队列的大致大小。
为什么不能返回这个队列的确切大小呢?我理解队列可能会被多个线程访问,但在我调用函数的那一刻,似乎仍然可以返回那一时刻的确切大小。

1
什么时候?在方法返回期间,队列大小可能已经发生了变化。 - Martin James
2个回答

40

这是因为其他线程也在访问它。当你尝试使用从qsize()返回的大小时,队列可能已经改变。更好的文档应该像这样:

返回队列的大小。请注意,在多线程环境中,大小可能随时发生变化,这只是实际大小的近似值。


5
我认为“近似值”并不是最清晰的词语,但正如Ned所提到的,他们试图指出的是,仅仅因为在时间 t1 时队列的大小为7,并不意味着当你稍后推入或弹出值时它仍将是大小为7。
问题在于,在多线程环境下,假设从qsize返回的大小在你尝试推送/弹出队列中的值时仍然正确可能会产生意外行为。
例如:
q = Queue()
if q.qsize > 0: # size is 1 here
    # another thread runs here and gets an item from your queue
    # this get fails and throws an exception in your thread:
    item = q.get(False)
    # do whatever processing with item you need to do

这是一个LBYL(先行判断再执行)的例子,当多个线程同时访问队列时,可能会存在潜在的竞态条件,因此这种做法比较危险。

在这种情况下,应该采用EAFP(宁愿请求原谅,也不要事先获得许可)的方式,可以按照以下操作进行:

from Queue import Queue, Empty
import time
q = Queue()
try:
    item = q.get(False)
    # do whatever processing with item you need to do 
except Empty:
    time.sleep(1)

或者只需使用信号量来保证队列中有条目。 - Martin James
6
队列已经同步,不要再添加更多。在多线程中使用q.get和异常处理是最好的线程安全获取队列中数据的方式。 - Ned Batchelder
@NedBatchelder 我不理解你的评论。这难道不是在这里所做的事情吗? - Gulzar
我认为get方法在队列不为空但另一个线程正在访问它(例如放置另一个项目)的情况下也可能会被阻塞。在这种情况下,似乎仍然会抛出Empty异常,尽管队列不为空。 - Simeon Borko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接