gunicorn + gevent 能显著提升 flask 的 i/o 密集型并发能力,但必须按顺序完成 monkey.patch_all()、正确选 worker 类、调大连接池,否则会退化成同步模型甚至更慢。

直接上结论:Gunicorn + gevent 能显著提升 Flask 的 I/O 密集型并发能力,但必须按顺序完成 monkey.patch_all()、正确选 worker 类、调大连接池,否则它会退化成同步模型,甚至比默认 sync 更慢。
为什么加了 --worker-class gevent 还是卡顿
根本原因是 gevent 没真正生效——最常见的是 monkey.patch_all() 没加,或加得太晚。gevent 依赖 patch 标准库(尤其是 socket、ssl、thread),漏一个就可能让整个协程挂起。
-
monkey.patch_all()必须放在应用入口文件(如app.py)的最顶部,在任何import可能触发网络/IO 的模块(比如requests、psycopg2、urllib)之前 - 如果用了
Flask-SQLAlchemy,确保SQLALCHEMY_POOL_SIZE≥--worker-connections × --workers,否则连接池抢不到连接,所有请求都在等 - 日志里出现
BlockingIOError或大量超时但 CPU 很低,基本可断定 patch 失败或被未 patch 的库阻塞
gunicorn 启动命令里哪些参数不能省
只写 gunicorn -w 4 -k gevent app:app 是危险的默认配置。以下三项必须显式指定或验证:
-
--worker-connections 1000:每个 gevent worker 最大协程数,默认虽是 1000,但若机器内存小(比如 1GB RAM),建议降到 256 或 512,避免 OOM -
--timeout 30:防止某个协程卡死拖垮整个 worker;低于 10 秒易误杀正常长请求,高于 60 秒可能掩盖阻塞问题 -
--log-level info:启动时能看到实际加载的 worker 数、connections 数、使用的 class,避免“以为起了 4 个 gevent,其实只起了 1 个 sync”
哪些代码会悄悄让 gevent 失效
不是所有 Python 代码都兼容 gevent 协程。以下操作一旦出现在请求处理路径中,就会导致当前 worker 阻塞,失去并发优势:
图片提示词生成器?不止如此。 马甲系统 —— 把脑海中的画面,翻译成AI能理解的专业表达。 用得越多,它越懂你:首次需要多问几句确认方向,用久了几乎一说就懂。 用得越多,它越快:缓存机制让后续对话越来越省。 RAG进化:成功案例持续入库,越跑越聪明。 输入「新手指南」查看完整功能介绍
- 原生
time.sleep(1)→ 改用gevent.sleep(1) - 未 patch 的
requests.get()→ 要么装gevent-requests,要么确认monkey.patch_all()已执行(它会 patchsocket和ssl) - 直接调用
subprocess.Popen→ 它不走 socket,patch 不到,得换gevent.subprocess或改用异步方案 - 用了
threading.Thread或concurrent.futures.ThreadPoolExecutor→ 协程无法调度线程,整个 worker 被锁住
本地验证 gevent 是否真在跑
别靠压测结果猜。最简单的方法是启动时加 --preload 和 --log-level debug,然后看日志里有没有这行:
Booting worker with pid: XXX<br>Worker connections: 1000<br>Worker class: gevent
再写个临时路由检查当前线程和 greenlet ID:
@app.route('/debug')<br>def debug():<br> import threading, gevent.greenlet<br> return {<br> 'thread_id': threading.get_ident(),<br> 'greenlet_id': id(gevent.greenlet.getcurrent()),<br> 'is_gevent': 'gevent' in str(type(gevent.greenlet.getcurrent()))<br> }
并发 curl 几次,如果 thread_id 基本不变而 greenlet_id 全不同,说明 gevent 在正常调度;如果 thread_id 变来变去,说明你还在用 sync 模式或者 patch 失败。
最容易被忽略的是:gevent 对错误堆栈不友好,一旦出错,traceback 可能跳过协程上下文,看起来像“没报错却卡死”。所以务必先确认 patch 和 worker class 正确,再排查业务逻辑。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










