Python Flask + Tornado 请求很慢的接口导致全站无法访问,有什么解决方法么?

2021-08-13 12:50:30 +08:00
 rv54ntjwfm3ug8

第一次写 Flask,一个网页返回前需要请求一个要 5s 左右才能返回结果的接口,对方要求不能用 ajax,但一旦发起请求到请求完成前全站就无法打开了。按 Google 上找的教程做了多线程,但请求量大还是会导致全站无法打开,CPU 占用只有不到 1%,请问有什么解决方法么?

2599 次点击
所在节点    Python
17 条回复
learningman
2021-08-13 13:02:52 +08:00
协程,asyncio
Icarooooos
2021-08-13 13:06:57 +08:00
gunicorn
wzwwzw
2021-08-13 13:07:28 +08:00
看你的描述应该是直接用了 app.run 需要在外层套一层 web 服务器 gunicorn 了解下。
wellsc
2021-08-13 13:08:47 +08:00
profile 看下到底慢在哪个环节
rv54ntjwfm3ug8
2021-08-13 13:11:09 +08:00
@Icarooooos #2
@wzwwzw #3 感谢回复,已经用了 Tornado,按 Google 上的说法 Tornado 已经包含了一个异步 WSGI server,请问还有必要用 gunicorn 么?
rationa1cuzz
2021-08-13 13:34:10 +08:00
先找问题啊,你这问题都没找到瞎猜什么?先看是接口问题还是什么服务器问题,用个抓包工具像 4 楼的 profile 或者直接用 postman,本地调一下服务器调一下
Kinnice
2021-08-13 13:40:26 +08:00
5s 左右才能返回结果的接口 是实时数据还是弱实时的,如果是弱实时的,可以起个定时器定时去请求然后把结果缓存到本地,然后接口直接取本地的那个缓存结果
rv54ntjwfm3ug8
2021-08-13 13:43:27 +08:00
@rationa1cuzz #6 问题是一个需要较长时间返回的网页返回结果前网站的其它请求都无法处理,服务器上调也是这样。看起来是像只有一个线程, 于是去抄了一份 Tornado 异步的代码,但情况没有改善 paste.ubuntu.com/p/w2XNbbjDgh/
rv54ntjwfm3ug8
2021-08-13 13:43:46 +08:00
@Kinnice #7 是实时数据。
Kinnice
2021-08-13 13:47:34 +08:00
看这个问题,你好像需要改的是前端的问题,让前端先加载其他资源,最后再加载这个,
另外就是你的这个接口怎么会这么慢是做了什么操作
vicalloy
2021-08-13 13:53:58 +08:00
server = tornado.httpserver.HTTPServer(app)
server.bind(8888)
server.start(0) # forks one process per cpu
IOLoop.current().start()
把 server.start(0)改成 99
你的 web 服务器是单进程&单线程模式,一次只能有一个实例,你得想办法把线程 /进程数改打。
前面说到 asyncio 是行不通的,asyncio 有传播性,除非你的应用本身就是 asyncio 写的,不然不会有任何改善。
stach
2021-08-13 14:15:47 +08:00
- 1. 不要用 tornado, 你显然搞不定
- 2. 百度一下怎么用 gevent monkey patch flask
- 3. 最好用 gunicorn 部署 flask
tisswb
2021-08-13 14:17:45 +08:00
楼上正解
tonghuashuai
2021-08-13 14:22:47 +08:00
wsgi 应用是同步的,如用 wsgi server 再是单线程单进程的,就相当于你这个 web 服务是一个单线程 /进程同步服务,同时只能处理一个任务。Tornado 框架可以解决,看来是姿势不对了。所以解决办法可以是下面的几种:

1. 保持单线程,但 fork 多个进程,类似于启动多个你这个服务,#11 楼的办法可以参考下,或者 gunicorn 替换 tornado,gunicorn --workers=4 main:app (启动 4 个 worker 进程,也就是能支持 4 个请求同时访问你的耗时接口)
2. 改进,多进程多线程,gunicorn 替换 tornado (考虑加 gevent ),gunicorn --workers=4 --threads=4 main:app,并发请求数就是 worker * 线程
no1xsyzy
2021-08-13 15:02:28 +08:00
考虑到通常来说计算不会超过 100ms,你的线程池 size 至少是 50
拿 tornado 作框架你需要手动新建线程池或者 ThreadPoolExecutor
Trim21
2021-08-13 17:02:18 +08:00
要么直说用 gunicorn 来运行 flask,要么直接用 tornado+async 来写后端,建议前者
qiuhang
2021-08-13 19:51:00 +08:00
你这似乎是以单进程但线程提供服务,某个请求卡住后就没有其它 responder 了,可以尝试开多进程,或者开协程。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/795550

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX