引子
单纯 gevent 跟 nodejs 一样有个问题是如果服务器有大的同步计算 (比如压缩一张图片什么的) 需求时, 服务器会很卡. 这也不能怪它们, 因为本来它们的长处是 IO 异步化, 同步计算卡住是然, 或荐
正文
嘛, 一番探索之后配了下面一个用例 (Flask)import time
import flask
app = flask.Flask(__name__)
@app.route('/<int:n>')
def root(n):
time.sleep(2)
i = n / 2
while 1 < i:
if n % i == 0:
return 'not prime'
i -= 1
return 'prime'
if __name__ == '__main__':
app.run(port=8000)
ab -n 500 -c 50 localhost:8000/16785407
-c 50
这个参数纯是卖萌的, 因为上面这代码自身根本异步不起来. 结果自然是惨不忍睹, 重点两行在测试机上表现如下Time per request: 131417.472 [ms] (mean)
Time per request: 2628.349 [ms] (mean, across all concurrent requests)
安装 gunicorn 可以直接通过 pip 安装, 简单容易, 就不废话了. 下面上 gunicorn 平装版, 把上面的文件保存为 test.py, 在控制台中执行
gunicorn -w 4 test:app
app
(就是文件里全局定义的 app
变量啦). 现在再开 ab 来一炮 (参数完全相同), 结果是Time per request: 33150.026 [ms] (mean)
Time per request: 663.001 [ms] (mean, across all concurrent requests)
虽然有 4 个进程睡睡醒醒轮番搞, 但没有异步 IO 的支持, 进程睡着就不干事了. 作为要榨干 worker 进程以及 CPU 使用率的系统管理员来说这可不能忍, 于是继续折腾个 gevent 进去好了, 两者互补, 相得益彰.
不过用 gunicorn 就不需要在文件最开始打猴子补丁了, gunicorn 有个参数直接让 gevent 嵌入进程
gunicorn -w 4 -k gevent test:app
Time per request: 9724.214 [ms] (mean)
Time per request: 194.484 [ms] (mean, across all concurrent requests)
补充说明
绑定其它端口
gunicorn -b 0.0.0.0:8000 -w 4 -k gevent test:app
我没有定义在全局的 app / 我的 app 需要特殊的初始化方式
假如在文件里以一个特别的函数初始化app
, 比如def init_app(arg0, arg1):
# ...
return app
gunicorn -b 0.0.0.0:8000 -w 4 -k gevent 'test:init_app("value0", "value1")'
感谢双木成林对这篇文章的指导与建议.