【问题标题】:How to iterate through a Python Queue.Queue with a for loop instead of a while loop?如何使用 for 循环而不是 while 循环遍历 Python Queue.Queue?
【发布时间】:2014-01-16 09:20:29
【问题描述】:

通常我们这样编码:

while True:
    job = queue.get()
    ...

但是是否也可以按照以下方式做一些事情:

for job in queue.get():
    #do stuff to job

我想这样做的真正原因是因为我想使用 python-progressbar 的自动检测 maxval。他们这样做就像for this in progressbar(that):

【问题讨论】:

标签: python


【解决方案1】:

您可以将iter 与可调用对象一起使用。 (您应该传递两个参数,一个用于可调用对象,另一个用于标记值)

for job in iter(queue.get, None): # Replace `None` as you need.
    # do stuff with job

注意 当没有元素剩余并且没有放置哨兵值时,这将阻塞。此外,与 while-get 循环一样,与普通的 for 循环不同的是,它会从队列中删除项目。

None 是通用值,所以这里有一个更具体的哨兵值示例:

sentinel = object()
for job in iter(queue.get, sentinel):
    # do stuff with job

【讨论】:

  • @majimboo,你把join放在哪里?你能更新问题中的代码吗?
  • @falsetru,啊,我明白了。但问题是当没有数据时的最后一部分错误。这是为什么?因为没有哨兵值?
  • @majimboo,在正常作业相关值后添加一个标记值(答案代码中的None)。 queue.put(None)
  • @micahscopes,我在NOTE 部分提到了这一点。 Python 2.x 也是如此。
  • @falsetru 没错,这只是一个例子,但最好显示一个更合适的哨兵值,因为 None 通常是一个糟糕的选择
【解决方案2】:

我想说这是在某些方面迭代队列的简单方法:

from queue import Queue

q = Queue()
q.put(1)
q.put(2)
q.put(3)

for i in q.queue:
    print(i)

【讨论】:

  • 我认为如果您使用线程执行此操作,可能需要锁定队列。您也许可以为此使用 queue.mutex,但它没有记录在案,所以我不能 100% 确定。
  • @href_ :不,这是错误的! queue.Queue 是自动线程安全的,mp.Queue 是自动进程安全的。事实上,使用队列提供排序是一种经过时间考验的编写并发程序的方法,很容易证明是正确的。
【解决方案3】:

对于那种队列,实际上我通常不会使用queue.empty() 的检查,因为我总是在线程上下文中使用它,因此无法知道另一个线程是否会在几毫秒内将某些东西放入其中(因此该检查将反正没用)。我从不检查队列是否为空。我宁愿使用标记生产者结束的哨兵值。

所以我更喜欢使用iter(queue.get, Sentinel)

如果您知道没有其他线程将项目放入队列中并且只想从所有当前包含的项目中排出它,那么您可以这样使用:

class Drainer(object):
  def __init__(self, q):
    self.q = q
  def __iter__(self):
    while True:
      try:
        yield self.q.get_nowait()
      except queue.Empty:  # on python 2 use Queue.Empty
        break

for item in Drainer(q):
  print(item)

def drain(q):
  while True:
    try:
      yield q.get_nowait()
    except queue.Empty:  # on python 2 use Queue.Empty
      break

for item in drain(q):
  print(item)

【讨论】:

  • python 2.7,说AttributeError: class Queue has no attribute 'Empty'
  • 在 Python 2.7 上 import Queue 之后使用 Queue.Empty。或者使用from Queue import Empty,然后只期望Empty被抛出。
  • 2.7 的问题是模块和类都有名称 Queue 并且取决于您的 import 声明,您指的是其中一个。
  • 不起作用。不等待队列任务完成。具体来说,需要在任务完成时检查它们。
  • @mathtick 你是对的,那里没有等待队列任务完成的东西。这不是要求的。虽然它可以很容易地添加,所以请随意询问有关等待队列任务完成的问题,在那里您可以提供特定设置的所有详细信息(这似乎与此处的设置不同)。
【解决方案4】:

我的第一个虽然是针对 iter 函数,但内置队列模块不返回哨兵,所以一个不错的选择可能是定义自己的包装类:

import Queue

class IterableQueue():
    def __init__(self,source_queue):
            self.source_queue = source_queue
    def __iter__(self):
        while True:
            try:
               yield self.source_queue.get_nowait()
            except Queue.Empty:
               return

这个迭代器包装队列并产生直到队列为空,然后返回,所以现在你可以这样做:

q = Queue.Queue()
q.put(1)
q.put(2)
q.put(3)

for n in IterableQueue(q):
    print(n)

输出:

1
2
3

这个方法有点冗长,如果有人知道使用内置函数更好的东西会很有趣。

【讨论】:

  • 我能想到的最好的办法就是让它成为队列的子类。然后你可以删除__init__方法。
【解决方案5】:

我想这是更简单的方法

for elem in list(q.queue):
      print(elem)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-06
    • 2017-03-05
    • 1970-01-01
    • 2016-01-26
    • 2018-07-30
    • 2019-11-11
    • 2020-08-14
    相关资源
    最近更新 更多