V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
theklf4
V2EX  ›  Python

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

  •  
  •   theklf4 · 115 天前 · 1446 次点击
    这是一个创建于 115 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    第 1 条附言  ·  115 天前
    问题是一个需要较长时间返回的网页返回结果前网站的其它请求都无法处理,服务器上调也是这样。看起来像只有一个线程, 于是去抄了一份 Tornado 异步的代码,但情况没有改善 paste.ubuntu.com/p/w2XNbbjDgh/
    17 条回复    2021-08-13 19:51:00 +08:00
    learningman
        1
    learningman  
       115 天前
    协程,asyncio
    Icarooooos
        2
    Icarooooos  
       115 天前 via Android
    gunicorn
    wzwwzw
        3
    wzwwzw  
       115 天前
    看你的描述应该是直接用了 app.run 需要在外层套一层 web 服务器 gunicorn 了解下。
    wellsc
        4
    wellsc  
       115 天前
    profile 看下到底慢在哪个环节
    theklf4
        5
    theklf4  
    OP
       115 天前
    @Icarooooos #2
    @wzwwzw #3 感谢回复,已经用了 Tornado,按 Google 上的说法 Tornado 已经包含了一个异步 WSGI server,请问还有必要用 gunicorn 么?
    rationa1cuzz
        6
    rationa1cuzz  
       115 天前
    先找问题啊,你这问题都没找到瞎猜什么?先看是接口问题还是什么服务器问题,用个抓包工具像 4 楼的 profile 或者直接用 postman,本地调一下服务器调一下
    Kinnice
        7
    Kinnice  
       115 天前
    5s 左右才能返回结果的接口 是实时数据还是弱实时的,如果是弱实时的,可以起个定时器定时去请求然后把结果缓存到本地,然后接口直接取本地的那个缓存结果
    theklf4
        8
    theklf4  
    OP
       115 天前
    @rationa1cuzz #6 问题是一个需要较长时间返回的网页返回结果前网站的其它请求都无法处理,服务器上调也是这样。看起来是像只有一个线程, 于是去抄了一份 Tornado 异步的代码,但情况没有改善 paste.ubuntu.com/p/w2XNbbjDgh/
    theklf4
        9
    theklf4  
    OP
       115 天前
    @Kinnice #7 是实时数据。
    Kinnice
        10
    Kinnice  
       115 天前
    看这个问题,你好像需要改的是前端的问题,让前端先加载其他资源,最后再加载这个,
    另外就是你的这个接口怎么会这么慢是做了什么操作
    vicalloy
        11
    vicalloy  
       115 天前
    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
        12
    stach  
       115 天前   ❤️ 3
    - 1. 不要用 tornado, 你显然搞不定
    - 2. 百度一下怎么用 gevent monkey patch flask
    - 3. 最好用 gunicorn 部署 flask
    tisswb
        13
    tisswb  
       115 天前
    楼上正解
    tonghuashuai
        14
    tonghuashuai  
       115 天前   ❤️ 1
    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
        15
    no1xsyzy  
       115 天前
    考虑到通常来说计算不会超过 100ms,你的线程池 size 至少是 50
    拿 tornado 作框架你需要手动新建线程池或者 ThreadPoolExecutor
    Trim21
        16
    Trim21  
       115 天前 via Android   ❤️ 1
    要么直说用 gunicorn 来运行 flask,要么直接用 tornado+async 来写后端,建议前者
    qiuhang
        17
    qiuhang  
       115 天前
    你这似乎是以单进程但线程提供服务,某个请求卡住后就没有其它 responder 了,可以尝试开多进程,或者开协程。
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2306 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 18ms · UTC 15:45 · PVG 23:45 · LAX 07:45 · JFK 10:45
    ♥ Do have faith in what you're doing.