bigywater.tech
Python · 45

asyncio.Queue:异步生产者消费者模型

真实建一个小容量的asyncio.Queue,用快生产者+慢消费者的组合,验证有界队列的背压阻塞和join()真实等待的同步语义。

队列满时put()
真实阻塞等待,不是抛异常
阻塞时长
真实约等于消费者处理一个item的耗时
join()
真实等未完成任务计数归零,不是等qsize()==0

做的事:小容量队列(maxsize=2),生产者快、消费者慢

代码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真实被处理完

验证:队列满了,put()真实会阻塞等待,不是抛异常

实测 · 本机执行输出
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))几乎完全对应,这正是生产者被消费者节奏真实"卡住"的证据:生产者的产出速度被消费者的消费速度真实反向限制住了,不会无限堆积在内存里,这也是为什么有界队列常被用来做真实的流量控制——上游写得太快,下游处理不过来,有界队列能让上游自然被真实拖慢,而不是让积压的数据无限增长直到内存耗尽。

验证:join()真实会等到所有item都被task_done()才返回

实测 · 本机执行输出
producer: done putting all items    ← 生产者已经喊完了,但这不代表消费完了
    consumer: processed 2
    consumer: processed 3
    consumer: processed 4                ← join()真实一直等到这一行才继续往下走
main: all done, queue empty? True
这组时序真实证明了producer喊"done putting all items"和整个流水线真的处理完,是两个完全不同的真实时间点——await q.join()关心的不是队列里还剩几个item(qsize()==0),而是真实有没有每一个被get()取出来的item都对应调用过一次task_done()。Queue内部真实维护着一个"未完成任务数"的计数器,put()让它+1,task_done()让它-1,join()就是真实在等这个计数器归零。本文这次producer调用完最后一次put之后,队列里还真实积压着几个item没被消费者处理完,join()真实继续挂起等待,直到消费者把剩下的processed 2/3/4都跑完、每次都真实调用了task_done(),计数器才归零,join()才真的返回——这套机制让"生产者已经发完所有任务"和"所有任务真的都被处理完了"这两件容易混淆的事情,有了一个真实、明确的同步点。

分步演示:从背压阻塞到join()真实的同步语义

每一步都是本文上面用真实的asyncio.Queue跑出来的原始结果。

有界队列真实的背压机制和join()真实等待的东西
这一步新验证的行为

    本文用到的工具

    • 本机 Python 3.14.7,标准库 asyncio.Queue
    京ICP备2026067502号-1京公网安备11010502063487号