真实建一个小容量的asyncio.Queue,用快生产者+慢消费者的组合,验证有界队列的背压阻塞和join()真实等待的同步语义。
代码async def producer(q, n): for i in range(n): await q.put(i) # 队列满时会真实在这里await等待 async def consumer(q): while True: item = await q.get() if item is None: q.task_done(); break await asyncio.sleep(0.05) # 模拟处理耗时 q.task_done() q = asyncio.Queue(maxsize=2) cons = asyncio.create_task(consumer(q)) await producer(q, 5) await q.put(None) await q.join() # 等所有item真实被处理完
producer: put(0) immediate, qsize=1
producer: put(1) immediate, qsize=2 ← 已经到maxsize了
consumer: processed 0 ← 消费者腾出了一个位置
producer: put(3) blocked for 0.052s (queue was full) ← 真实等了约一次消费耗时才放进去
consumer: processed 1
producer: put(4) blocked for 0.052s (queue was full) ← 真实同样等待
producer: done putting all items这是asyncio.Queue(maxsize=N)真实的背压(backpressure)机制:队列满的时候,await q.put(...)不会抛异常也不会丢弹出,而是真实挂起在那个await点,一直等到消费者get()取走一个item腾出空位,才真实恢复执行——本文测出的阻塞时长(约0.052秒)跟消费者处理一个item的耗时(sleep(0.05))几乎完全对应,这正是生产者被消费者节奏真实"卡住"的证据:生产者的产出速度被消费者的消费速度真实反向限制住了,不会无限堆积在内存里,这也是为什么有界队列常被用来做真实的流量控制——上游写得太快,下游处理不过来,有界队列能让上游自然被真实拖慢,而不是让积压的数据无限增长直到内存耗尽。
producer: done putting all items ← 生产者已经喊完了,但这不代表消费完了
consumer: processed 2
consumer: processed 3
consumer: processed 4 ← join()真实一直等到这一行才继续往下走
main: all done, queue empty? True每一步都是本文上面用真实的asyncio.Queue跑出来的原始结果。
asyncio.Queue