错误,异步除外.队列.put



asyncio\queues.py

@coroutine
def put(self, item):
    """Put an item into the queue.
    Put an item into the queue. If the queue is full, wait until a free
    slot is available before adding item.
    This method is a coroutine.
    """
    while self.full():
        putter = futures.Future(loop=self._loop)
        self._putters.append(putter)
        try:
            yield from putter
        except:
            putter.cancel()  # Just in case putter is not done yet.
            if not self.full() and not putter.cancelled():
                # We were woken up by get_nowait(), but can't take
                # the call.  Wake up the next in line.
                self._wakeup_next(self._putters)
            raise
    return self.put_nowait(item)

在我看来,putter可以由cancelset_exceptionset_result来完成。CCD_ 5使用CCD_ 6。只有cancelset_exception会抛出异常,则会出现except:。我认为不需要except:

为什么要在Wake up the next in line中添加except:

更新:@VincentCCD_ 13调用CCD_ 14。CCD_ 15将执行CCD_ 16。CCD_ 17将返回False的CCD_ 18。因此,任务1将被取消

@Vincent非常感谢

关键原因是task.cancel可以取消任务,尽管正在等待的未来任务已设置为结果(self._state=_FINISHED)。

如果等待putter的任务被取消,yield from putter将引发一个CancelledError。这可能发生在调用get_nowait()之后,并且您希望确保通知其他推杆队列中有新的插槽可用。

这里有一个例子:

async def main():
    # Create a full queue
    queue = asyncio.Queue(1)
    await queue.put('A')
    # Schedule two putters as tasks
    task1 = asyncio.ensure_future(queue.put('B'))
    task2 = asyncio.ensure_future(queue.put('C'))
    await asyncio.sleep(0)
    # Make room in the queue, print 'A'
    print(queue.get_nowait())
    # Cancel task 1 before giving the control back to the event loop
    task1.cancel()
    # Thankfully, the putter in task 2 has been notified
    await task2
    # Print 'C'
    print(await queue.get())

编辑:关于内部情况的更多信息:

  • 调用queue.get_nowait():putter.set_result(None);推杆状态现在是FINISHED,并且task1将在控制返回到事件循环时唤醒
  • task1.cancel():task1._fut_waiter已经完成,因此task1._must_cancel被设置为True,以便在下次运行task1时引发CancelledError
  • await task2
    • 控制返回到控制回路,task1._step()运行。在协程中抛出一个CancelledErrortask1._coro.throw(CancelledError())
    • queue.put捕获异常。由于队列未满并且'B'不会被插入,因此必须通知队列中的下一个推杆:self._wakeup_next(self._putters)
    • 然后CCD_ 40被重新升起并且被捕获在CCD_ 41中。task1现在实际上取消了它自己(super().cancel()

最新更新