【问题标题】:How to slice a queue?如何切片队列?
【发布时间】:2018-08-16 18:16:02
【问题描述】:

我有一个循环处理的队列

while True:
    # a processing loop
    batch = []
    while True:
        e = q.get()
        if e:
            batch.append(e)
        else:
            # the queue is empty
            break
    do_something_with(batch)
    # wait a moment before emptying the queue again
    time.sleep(2)

这个想法是清空队列,处理其内容并等待片刻,然后再次检查内容。

我有时会遇到一个竞争条件,当我 get() 一个元素时,队列被填充,我最终得到一个不断增长的 batch,它永远不会被进一步处理。

一种解决方案是检查batch 大小并在大小合适时对其进行处理。如果我没有太多事件进入队列并且batch 从未达到正确的大小,这将不起作用 - 但我需要处理事件(无论它们的数量是多少)而不是等到足够的累积。

第二种解决方案是根据大小和batch 空闲的时间来构建检查——这会使代码过于复杂。

一个好的解决方案是“一次从队列中获取n 元素”。我在文档中找不到类似的东西。 有没有办法一次从队列中弹出多个元素(例如对列表进行切片)?

【问题讨论】:

    标签: python python-3.x queue


    【解决方案1】:

    Queue.get 默认阻止;无限循环的来源。

    Queue.get(block=True, timeout=None)

    从队列中删除并返回一个项目。 如果可选的 args 块是 true 并且 timeout 是 None (默认值),如有必要,阻止,直到 item 可用。 如果 timeout 为正数,则最多阻塞 timeout 秒,如果没有项目,则引发 Empty 异常 在那段时间内可用。否则(块为假),返回一个项目 如果一个立即可用,则引发 Empty 异常 (在这种情况下会忽略超时)。

    您应该使用 Queue.get_nowaitQueue.get(block=False) 来防止阻塞。或者队列为空时使用Queue.get(timeout=<seconds>),最多等待<seconds>

    您的问题中提到的解决方案听起来不错:

    BATCH_SIZE = 10
    
    while True:
        batch = []
    
        # Get out of loop if enough item collected or queue is empty
        while len(batch) < BATCH_SIZE:
            try:
                e = q.get_nowait()  # OR q.get(timeout=0.1)
            except Empty:
                break
                # To prevent empty batch
                # if batch:
                #     break
    
        do_something_with(batch)
        # wait a moment before emptying the queue again
        time.sleep(2)
    

    【讨论】:

    • 我使用了类似的解决方法(我也将其作为解决方案发布)。如果没有足够的元素,你的方法不会让我离开while,对吧?另外,e 没有添加到批处理中(轻微忽略)
    • @WoJ, get_nowait() 将引发 queue.Empty 异常;即使batch 中有 's&lt;BATCH_SIZE 项,它也会让你脱离while(内部)。
    • @WoJ,为防止,清空batch,可以将break替换为if batch: break
    • @WoJ,如果您不想在队列为空的情况下忙循环,则将q.get_nowait() 替换为q.get(timeout=0.1)
    【解决方案2】:

    我现在使用的解决方法,直到有更好的想法/解决方案:

    while True:
        # get up to 1000 elements form the queue
        batch = []
        for _ in range(1000):
            try:
                e = q.get(block=False)
            except queue.Empty:
                continue
            else:
                batch.append(e)
        do_something_with(batch)
        time.sleep(2)
    

    我可能会进行 1000 次无用的尝试来获取一个元素(队列为空),或者全部尝试(即使队列增长),或者介于两者之间的任何尝试

    【讨论】:

      猜你喜欢
      • 2012-04-17
      • 1970-01-01
      • 2018-11-21
      • 2015-02-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-28
      相关资源
      最近更新 更多