必须在导入任何网络模块前执行 monkey.patch_all(),否则 requests、Flask-SQLAlchemy 等提前导入的模块将导致协程静默失效;gunicorn -k gevent 必须配合 --worker-connections 显式配置,且业务代码需避免 time.sleep、threading、未 patch 的 I/O 库等阻塞操作。

必须在导入任何网络模块前执行 monkey.patch_all()
gevent 不是靠参数“激活”的,它靠的是对 Python 标准库的运行时替换(patch)。如果 socket、ssl、threading 等模块已在 patch 前被其他库(比如 requests、flask_sqlalchemy)提前导入,那后续所有协程调度都会静默失效——请求仍会阻塞,但你完全看不出报错。
正确做法是在 app.py(或 Gunicorn 入口文件)最顶部、任何 import 语句之前插入:
from gevent import monkey monkey.patch_all()
常见错误包括:
- 把这行放在
from flask import Flask后面 - 在
requirements.txt里装了requests,但没确认它是否被 patch(HTTPS 请求尤其容易卡住) - 用了
Flask-SQLAlchemy并在 patch 前就初始化了db = SQLAlchemy(app),导致底层 psycopg2 或 pymysql 连接池绕过协程
gunicorn -k gevent 必须配合 --worker-connections
只写 gunicorn -w 4 -k gevent app:app 是无效配置。默认 --worker-connections 是 1000,但 Gunicorn 不会主动校验你是否真 patch 成功;它只是按数字开协程槽位,而没 patch 的话,每个槽位仍是同步阻塞的。
立即学习“Python免费学习笔记(深入)”;
显式指定并匹配实际资源:
-
--worker-connections 512:适合 2GB 内存以下的机器,避免内存耗尽 -
-w 3:设为 CPU 核心数 × 1~1.5(不是越多越好,gevent worker 本身不占多核,多进程由-w控制) -
--timeout 60:防止某个未 patch 的time.sleep()或死循环拖垮整个 worker
漏掉 --worker-connections,-k gevent 就只剩个空壳,QPS 几乎不涨。
SkillSub Pro - Python 题解与代码注释双功能技能功能概述SkillSub Pro - Python 题解与代码注释双功能技能是一项面向实际任务的技能,主要用于SkillSub Pro 是一个 Python 题解生成与代码注释的 双功能合体技能 ,专为学生、算法学习者和开发者设计;✅ 一个技能,两种用途 :;核心要点📝 题解模式 :输入题目/题号,自动生成完整 Python 题解(含详细注释、解题思路、复杂度分析);💬 注释模式 :输入 Python 代码,自动添加详细中。它将相关步骤、
哪些代码会让 gevent 协程当场失效
即使 patch 正确、参数齐全,只要请求处理路径中出现以下任意一种,当前 worker 就会退化成单线程同步模型:
- 调用原生
time.sleep(1)→ 改用gevent.sleep(1) - 使用未 patch 的
subprocess.Popen→ 换gevent.subprocess或移出请求链路 - 启动
threading.Thread或ThreadPoolExecutor→ 协程无法调度线程,整个 worker 被锁死 - 用了未打补丁的
redis-py或旧版pymysql→ 确认驱动支持 gevent,或改用aioredis/asyncmy(但需重构)
特别注意:Flask 的 before_request 和 teardown_request 回调里也得遵守这些规则。
验证 gevent 是否真在跑,别靠压测猜
启动时加 --log-level debug --preload,然后看日志里有没有这行:
[INFO] Starting gevent arbiter [DEBUG] Arbiter starting with 4 workers (gevent)
再加个临时路由快速验证:
@app.route('/health')
def health():
import gevent
return {'pid': os.getpid(), 'greenlets': len(gevent.hub.Hub._pending)}
并发 curl 多次,如果 greenlets 数明显增长(比如从 1 到 80+),说明协程正在调度;如果始终是 1 或缓慢递增,基本就是 patch 失效或被阻塞了。
真正难的从来不是加参数,而是确保 patch 生效、I/O 库兼容、以及所有业务代码都落在协程安全区里——这三个环节只要一个断掉,整个异步链就坍缩回同步模型。

















