q = asyncio.Queue(maxsize=1000)
await q.put(item)   # 满时会挂起生产者
item = await q.get()

爬虫把解析出的链接全部 put 进队列,消费者慢得多,跑了半小时进程内存从三百兆涨到六吉,最后被系统杀掉。先别急着动参数,把报错原文和时间点记下来,顺序反了容易白折腾。

原因不复杂,Queue 默认 maxsize 为零表示无界,生产端从不等待,元素在内存里无限累积,消费速度跟不上时堆积就全部压在进程堆上,直到被系统杀掉。

围绕「asyncio 队列背压」排查时,命令行跑一遍比在面板里点十次有用,面板会替你做掉不少隐式操作。改完隔一天再看一次,当场正常不代表能稳住。

测试环境和线上的差别,往往就在版本号和那几行被忽略的配置上。

处理上按这个顺序:创建队列时就给出 maxsize,让生产端在队列满的时候挂起等待;消费端一次按批取走,减少 await 来回切换带来的额外开销;入口再补一层限流,别让上游无限往里灌数据,撑爆内存。

改完只确认一件事:进程内存曲线很快走平,队列长度稳定在上限附近,不再一路往上涨。

作者 9823189