推理基础设施 · Python6.4 asyncio.Queue:推理请求的"传送带"
06
asyncio 基础 · 4 / 5

6.4 asyncio.Queue:推理请求的"传送带"

💡 推理服务的核心架构:producer 收请求塞 queue,consumer 从 queue 取出来调 GPU

6.4 asyncio.Queue

协程安全的 FIFO 队列

import asyncio

async def producer(q, items):
    for x in items:
        await q.put(x)
        print(f"put {x}")

async def consumer(q, name):
    while True:
        item = await q.get()
        if item is None:        # 哨兵
            q.task_done()
            break
        print(f"{name} got {item}")
        q.task_done()

async def main():
    q = asyncio.Queue()
    await asyncio.gather(
        producer(q, [1, 2, 3]),
        consumer(q, "c1"),
    )
    await q.put(None)            # 让 consumer 退出

asyncio.run(main())

三个核心方法

  • await q.put(item):塞一个(队列满则等待)
  • await q.get():取一个(队列空则等待)
  • q.task_done():告诉队列“我处理完了”(用于 join

示范

import asyncio

async def main():
    q = asyncio.Queue()
    await q.put("a")
    await q.put("b")
    print(await q.get())    # a
    print(await q.get())    # b

✍️ 练习

写一个 mini 推理 pipeline:

  1. producer(q, backpressure):把每个 backpressure await q.put 进队列,最后 await q.put(None) 放哨兵
  2. consumer(q):循环 await q.get(),拿到 None 就 break,否则 print(f"infer: {item}"),模拟 await asyncio.sleep(0.05)
  3. main 里创建 Queue,先 gather producer 和 consumer,然后等待队列空(await q.join()

测试 backpressure = ["p1", "p2", "p3", "p4"]

💡 思路提示

点开看提示
  1. asyncio.Queue() 默认无限大,要限制就传 maxsize=...
  2. q.join() 会一直等到所有 put 进去的 item 都被 task_done
  3. 哨兵 None 是惯例告诉 consumer “没了,退出吧”

✅ 参考解法

写不出来再打开
import asyncio

async def producer(q, backpressure):
    for p in backpressure:
        await q.put(p)
    await q.put(None)

async def consumer(q):
    while True:
        item = await q.get()
        if item is None:
            q.task_done()
            break
        await asyncio.sleep(0.05)
        print(f"infer: {item}")
        q.task_done()

async def main():
    q = asyncio.Queue()
    await asyncio.gather(
        producer(q, ["p1", "p2", "p3", "p4"]),
        consumer(q),
    )
    await q.join()
    print("all done")

asyncio.run(main())

🔍 进阶思考

如果有多个 consumer + 1 个 producer,怎么写?

await asyncio.gather(
    producer(q, items),
    consumer(q),
    consumer(q),
    consumer(q),
)

Queue 自动负载均衡——空闲的 consumer 抢下一个 item。这就是为什么推理服务几乎都用 queue + 多个 worker。