windows flask 多进程高并发

最近在做的一个项目,需要将十几个python函数封装程flask服务供外界调用,每个函数之间没有什么关系,相互独立。虽然感觉不是很难,但因为用的windows系统,遇到的坑比较多,在此一一总结一下。

flask偶尔出现卡死问题

上一篇文章

不能高并发问题

因为十几个函数都要被调用,而且调用量不小,对响应时效性有较高要求,需要能充分利用CPU并行计算,采用了如下几个解决方法

1.flask + gevent + multiprocess + wsgi

在网上搜到这个解决方案

但不知道是系统原因还是我的算法原因,运行之后发现CPU占用量比较低,而且同时收到服务请求后是串行计算并返回的。看来这种方法在我这种情况下并不适用。

2.设置多线程

还有一个解决方法是代码运行时设置多线程,即输入命令

python 文件名.py runserver --threaded

但发现依然没有并行计算

3.设置多进程

这个解决方案是在代码的app.run()函数中设置process=n,n就是你想要的进程数。但设置之后报错,说是不能同时设置多线程和多进程。然后又在app.run()中设置threaded=False,发现又报错,可能是这个功能只支持linux系统而不支持windows

还看到nginx和gunicorn的方法,但是不知道这个对windows是否支持,而且好像有点麻烦就没有试

4.手动负载均衡

通过测试发现一个现象,就是flask并非完全串行,当同时接收到2个请求,如果执行第一个请求会占用计算资源,那么就是算完第一个再算第二个,而如果第一个请求的计算是等待(比如time.sleep)或者挂起状态,则会同时去处理第二个请求而不用等到第一个请求返回结果。

因此想到了一个解决方法,就是每个函数都单独启一个flask服务,对于耗时比较长的函数根据需求多启几个服务,每个服务设置的端口号不同,然后再启动一个对外的flask服务,外界所有请求都发送到这一个flask端口,然后这个端口内部再向对应的flask服务发送请求。

原始flask代码:

python 复制代码
from flask import Flask, render_template
from gevent.pywsgi import WSGIServer
from gevent import monkey
import time
import json

monkey.patch_all()
app = Flask(__name__)

@app.route('/')
def connect():
	return "connected test"

@app.route('/index')
def index_test():
	time0 = time.time()
	for i in range(10000):
		j = list(range(1000))
	print(time.time() - time0)
	res = {'data':1}
	res = json.dumps(res)
	return res

if __name__ == "__main__":
	server  = WSGIServer(("0.0.0.0", 5000), app)
	print("Server started")
	server.serve_forever()

测试调用代码:

python 复制代码
import requests
from threading import Thread
import time
def req():
    time0 = time.time()
    res = requests.get('http://127.0.0.1:5000/index')
    print(time.time() - time0)
    # print(res.text)
for i in range(5):
    th = Thread(target=req)
    th.start()

结果:

fask端显示的结果为

复制代码
0.5939996242523193
127.0.0.1 - - [2023-10-12 09:49:03] "GET /index HTTP/1.1" 200 127 0.600002
0.48799610137939453
127.0.0.1 - - [2023-10-12 09:49:04] "GET /index HTTP/1.1" 200 127 0.488996
0.5429947376251221
127.0.0.1 - - [2023-10-12 09:49:04] "GET /index HTTP/1.1" 200 127 0.544997
0.4839961528778076
127.0.0.1 - - [2023-10-12 09:49:05] "GET /index HTTP/1.1" 200 127 0.485996
0.4319908618927002
127.0.0.1 - - [2023-10-12 09:49:05] "GET /index HTTP/1.1" 200 127 0.434000

请求发送端显示的结果是

复制代码
1.0300004482269287
1.3990015983581543
1.8730018138885498
2.3450255393981934
2.831998586654663

收到返回的时间却在逐渐增加,说明没有并行计算

改进代码:

入口flask代码:

python 复制代码
from flask import Flask, render_template
from gevent.pywsgi import WSGIServer
from gevent import monkey
import requests
import time
import json

monkey.patch_all()
app = Flask(__name__)
path_num = {'num':-1}
@app.route('/')
def connect():
	return "connected test"

@app.route('/index')
def index_test():
	# time0 = time.time()
	# for i in range(10000):
	# 	j = list(range(1000))
	# print(time.time() - time0)
	# res = {'data':1}
	# res = json.dumps(res)
	if path_num['num'] > 4:
		path_num['num'] = 0
	else:
		path_num['num'] += 1
	num = path_num['num']
	url = f'http://127.0.0.1:{9030+num}/index'
	res = requests.post(url=url)
	return res.text

if __name__ == "__main__":
	server  = WSGIServer(("0.0.0.0", 5000), app)
	server.serve_forever()
	# app.run()

算法flask代码

python 复制代码
from flask import Flask, render_template
from gevent.pywsgi import WSGIServer
from gevent import monkey
import time
import json

monkey.patch_all()
app = Flask(__name__)

@app.route('/')
def connect():
	return "connected test"

@app.route('/index')
def index_test():
	time0 = time.time()
	for i in range(10000):
		j = list(range(1000))
	print(time.time() - time0)
	res = {'data':1}
	res = json.dumps(res)
	return res

if __name__ == "__main__":
	server  = WSGIServer(("0.0.0.0", 9030), app)
	print("Server started")
	server.serve_forever()
	# app.run()

这里的算法flask代码启动了5个,接口分别是9030~9034

用同样的方式测试,返回的结果为

复制代码
0.0500025749206543
0.05100274085998535
0.050002098083496094
0.05200028419494629
0.062003135681152344

差不多同时返回

总结

虽然最后一种方式有点麻烦,但可以解决现有问题,其中算法flask服务启动的越多性能越好。

相关推荐
用户8356290780519 小时前
Python 实现 PDF 文件加密与解密方法
后端·python
用户8356290780519 小时前
使用 Python 冻结与拆分 Excel 窗格教程
后端·python
你好潘先生17 小时前
别再记命令了,用 yeero do 说句人话就能跑脚本,而且不烧 token
服务器·python·命令行
Agent_大师17 小时前
WebSocket 行情重连成功,K线缺口不会自动消失
python
荣码17 小时前
LLM结构化输出:让AI返回JSON而不是废话,我踩了4个坑
java·python
copyer_xyf18 小时前
FastAPI 如何连接 MySQL
后端·python
apocelipes1 天前
常用编程语言和库的正则表达式性能对比
c语言·c++·python·性能优化·golang·开发工具和环境
用户8356290780511 天前
使用 Python 在 PDF 中创建与管理书签
后端·python
MeixianAgent2 天前
Python 回测数据入口怎么验?历史 K 线入库前先做 5 个检查
后端·python
咕白m6252 天前
用 Python 实现一键批量查找与替换 Excel 数据
后端·python