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
yuting0501
V2EX  ›  Python

请教一下 Flask + Requests + 多线程 问题

  •  
  •   yuting0501 · 2019-05-20 21:42:12 +08:00 · 3860 次点击
    这是一个创建于 2018 天前的主题,其中的信息可能已经有所发展或是发生改变。
    最近在做一个 Demo:
    [硬件 GPS 模块] 采集 GPS 数据发送到 [物联网服务器] , [我的网站] 定时 10 秒向 [物联网服务器] 请求 GPS 数据更新信息。

    现在遇到 requests 请求 gps 数据时候阻塞,导致网站卡顿,故想到使用 Python 的多线程解决:
    线程 A: 主线程,跑 flask
    线程 B:Requests 线程,睡眠 10 秒,唤醒请求 GPS 数据

    不考虑使用前端请求,就讨论用 Python 线程解决,如果是嵌入式的话可以这样做:
    1. 在线程 A 中创建低优先级的线程 B
    1. 有网络请求时执行线程 A,空闲时执行线程 B,这样既不影响用户网页请求,又可以发起 Requests 请求更新 GPS 数据

    回到 Flask 和 Python,查了一下 Flask 也有多线程模式,我尝试开启 threaded 选项,并未解决阻塞问题。

    查了 Python 3.7 的新特性,asyncio,能否使用 asyncio 解决多线程问题呢?

    对 Python 的理解很粗浅,顺便上两个没太理解的链接:
    https://hackernoon.com/how-to-run-asynchronous-web-requests-in-parallel-with-python-3-5-without-aiohttp-264dc0f8546

    https://medium.com/velotio-perspectives/an-introduction-to-asynchronous-programming-in-python-af0189a88bbb
    15 条回复    2019-06-01 08:25:58 +08:00
    coolair
        1
    coolair  
       2019-05-20 22:36:14 +08:00 via Android   ❤️ 1
    用 celery 啊
    im67
        2
    im67  
       2019-05-20 22:51:14 +08:00   ❤️ 1
    会不会是 flask 的多线程模式跟你要的多线程模式有区别?
    1iuh
        3
    1iuh  
       2019-05-20 23:22:07 +08:00   ❤️ 1
    gevent
    Qzier
        4
    Qzier  
       2019-05-20 23:37:14 +08:00   ❤️ 1
    几种解决方法:
    1. 多线程,不是让你开启 flask 的多线程模式,而是用 threading 模块再开启一个线程跑你的任务
    2. flask 换成 starlette,requests 换成 requests-async,全部写异步代码
    3. celery
    Qzier
        5
    Qzier  
       2019-05-20 23:39:17 +08:00
    4. 多进程,不是 CPU-bound 任务的话没必要,多线程就可以解决了
    rogwan
        6
    rogwan  
       2019-05-20 23:43:23 +08:00 via Android   ❤️ 1
    你这个阻塞是网络问题,不是机器性能问题。就算用 thread 消耗也不大,先优化下网络请求,不行再优化性能方面
    429839446
        7
    429839446  
       2019-05-21 00:06:59 +08:00   ❤️ 1
    不如 mqtt
    vZexc0m
        8
    vZexc0m  
       2019-05-21 11:51:19 +08:00   ❤️ 1
    你解决的问题的思路没对。
    1. 更新 GPS 数据应该采用异步定时任务实现,可用 celery 或者 dramatiq+apscheduler 实现。
    2. flask 部署采用 gunicorn+gevent 实现就行了。
    yuting0501
        9
    yuting0501  
    OP
       2019-05-21 12:39:52 +08:00
    谢谢大家!

    @vZexc0m @Qzier @coolair

    试了一下 celery,有点云里雾里的,只是想用多线程解决 Requests 阻塞问题,为什么 celery 要用到 redis,我再了解看看。
    1iuh
        10
    1iuh  
       2019-05-21 22:00:58 +08:00   ❤️ 1
    楼主呀,gevent 就是最好的解决方案。 不用上 celery。。
    CEBBCAT
        11
    CEBBCAT  
       2019-05-22 01:05:35 +08:00 via Android   ❤️ 1
    读起来真有点头疼,我翻来覆去看了三四遍也没看太懂。

    『现在遇到 requests 请求 gps 数据时候阻塞,导致网站卡顿,故想到使用 Python 的多线程解决:』

    1. requests 请求数据为什么会有阻塞?调物联网服务器接口不是调个 API 吗?几百 ms 吧?
    2. 网站为什么有卡顿?用户每次看网页都要从物联网服务器取数据呀?为什么不把数据准备好呢?
    3. 架构不明,不知道为什么使用多线程

    您可以使用 ProcessOn 绘制图片
    yuting0501
        12
    yuting0501  
    OP
       2019-05-22 09:51:37 +08:00
    @1iuh 感谢两次推荐,我去了解一下 gevent 用法。
    yuting0501
        13
    yuting0501  
    OP
       2019-05-22 10:16:23 +08:00   ❤️ 1
    @CEBBCAT 抱歉,背景可能没有交代清楚

    > 1. requests 请求数据为什么会有阻塞?调物联网服务器接口不是调个 API 吗?几百 ms 吧?
    这只是个 Demo,我的 Flask 网站调用物联网服务器接口,物联网服务器向 IOT 设备请求数据,IOT 设备返回给物联网服务器,物联网服务器再返回我的 Flask 网站,中间可能耗时 3、4 秒。简单来说姑且认为是一个 Requests 请求会耗时 3、4 秒。实际上即便几百 ms 也是不可接受的,requests 是阻塞请求,在此期间用户向我的网站请求网页无法得到及时响应。

    > 2. 网站为什么有卡顿?用户每次看网页都要从物联网服务器取数据呀?为什么不把数据准备好呢?
    可以准备好,例如在最新数据更新前先返回历史数据。但总会遇到 Requests 阻塞场景,想知道大家怎么解决。

    > 3. 架构不明,不知道为什么使用多线程
    简单来说,就做两件事情,
    1. 运行 Flask,响应网页请求
    2. 间隔 10 秒像第三方物联网服务器发起 Requests 请求

    矛盾冲突:
    由于 Requests 请求耗时较长,导致 Flask 程序无法及时响应网页请求。

    > 为什么使用多线程?
    可能用了错误的思维去解决这个问题,因为在嵌入式中,同优先级两个任务会共享 CPU 时间,时间片轮转,这样就能并行处理上述的两件事情。
    CEBBCAT
        14
    CEBBCAT  
       2019-05-22 13:06:23 +08:00
    @yuting0501 #13

    1. 为什么有阻塞
    噢!我现在明白多了。我想这是架构的问题——不知道架构这个取词是否洽当——,要是我来开发不会让数据每次都要这么走一遍的,各个节点都会有缓存 /数据库。要是换成 NBIOT 那种网络,你可能就不会让数据这么走了,嘻嘻。

    2. 可是使用缓存,但想问问大家怎么最优地解决 Requests 阻塞
    『总会遇到 Requests 阻塞场景』,在 Web 服务器(也就是 Flask 吧?)每秒更新一次数据,用的时候直接用 Web 服务器上积累下来的数据,这和普通的页面速度就一样了吧?

    我的意思可能是……解耦?

    3. 现在是什么架构?
    我想前两问可以体现我的思想了,再多的俺也不会了
    yuting0501
        15
    yuting0501  
    OP
       2019-06-01 08:25:58 +08:00
    @1iuh 再次感谢,gevent 是正确的解决方案。

    总结一下这个问题,用 threading 是不对的,Python 中的 threading 没有优先级区分,也就是说执行到 B 线程的 requests 耗时请求,CPU 还是会死等。同时 Python 的 threading 不能被销毁、停止、暂停、恢复或中断。

    什么情况下用 threading?
    当你每个 thread 中的任务的每行代码都是在干实事,没有等待、睡眠等无意义操作时可以用 threading。

    目前还在看资料,想搞懂有了 async 后是否还有使用 celery 和 gevent 的必要以及它们的区别。

    参考资料:
    https://docs.python.org/zh-cn/3.6/library/threading.html
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5925 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 02:58 · PVG 10:58 · LAX 18:58 · JFK 21:58
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.