Flask高并发需用gevent协程替代默认同步模型:monkey.patch_all()必须置于文件首行(早于所有import),Gunicorn须配置--worker-class gevent、--worker-connections和--timeout,数据库连接池需与协程规模匹配。

Flask 默认同步模型在 I/O 密集型场景下会迅速卡死,真正能撑住几百上千并发的,不是堆线程,而是用 gevent 把阻塞调用切走——但必须做对三件事:monkey.patch_all() 放最顶上、--worker-class gevent 显式指定、--worker-connections 合理设值,漏一个就退化成“假并发”。
gevent monkey.patch_all() 必须放在所有 import 之前
这不是风格问题,是执行顺序硬约束。一旦 requests、urllib、sqlalchemy 或任何用到 socket/ssl 的模块提前被导入,gevent 就 patch 不进去,后续所有 I/O(比如 requests.get()、数据库查询)都会阻塞整个协程栈。
-
错误写法:
import requests写在monkey.patch_all()前 → 请求卡在 HTTPS 调用,CPU 低但 QPS 断崖下跌 -
正确位置:在
app.py第一行(比from flask import Flask还早)写from gevent import monkey; monkey.patch_all() -
验证是否生效:启动日志里看到
Monkey patched字样;压测时观察 CPU 是否长期低于 30% 但 QPS 很高
Gunicorn 启动时必须显式配齐三个关键参数
只写 gunicorn -w 4 -k gevent app:app 是危险的默认配置。缺了下面任意一项,gevent 就只是个“带点异步味儿的普通 worker”,并发能力几乎不涨。
-
--worker-connections 1000:每个 gevent worker 最多处理 1000 个协程;内存小(如 1GB RAM)建议降到256或512,否则 OOM -
--timeout 30:防止某个未 patch 的库卡死拖垮整个 worker;设太低(60s)掩盖阻塞问题 -
--log-level info:必须加,否则看不到实际加载的是gevent还是 fallback 的syncworker
数据库连接池必须跟 gevent worker 规模匹配
SQLAlchemy 默认连接池大小(pool_size=5)完全扛不住 gevent 高并发。每个协程都可能尝试获取连接,池子不够就会排队等待,表现就是大量请求卡在 db.session.query(...) 上。
立即学习“Python免费学习笔记(深入)”;
-
SQLALCHEMY_POOL_SIZE至少设为--worker-connections × --workers,例如-w 4 --worker-connections 1000就要 ≥4000 - 务必启用
pool_pre_ping=True,防止协程复用已断开的连接导致InvalidRequestError - 避免在视图里用
time.sleep(1),必须换成gevent.sleep(1),否则直接挂起整个 worker
最容易被忽略的是:第三方 SDK(比如云厂商的 OSS/OCR Python SDK)如果内部用了原生 threading 或未 patch 的 socket,gevent 就会静默失效——得查文档确认兼容性,或换 SDK,或封装成子进程调用。



















