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

请教下各位 Gunicorn 启动时 Python 进程池

  •  
  •   cyberpoint · 2022-08-31 18:13:48 +08:00 · 2722 次点击
    这是一个创建于 816 天前的主题,其中的信息可能已经有所发展或是发生改变。

    大佬们问下 Python 多进程的问题

    功能概述

    发送一个请求 /task/create 开启了一个长耗时计算密集型任务。在这个任务运行的过程中,可以发送另一个请求 /task/close 来关闭这个任务。

    需求

    1. 需要可以主动关闭这个任务
    2. 优化长耗时任务

    目前的状况

    用 flask 建立了一个项目,通过 Gunicorn + Gevent 在 centos7 上部署了服务(尚未通过 Nginx 走代理)。

    问题

    为了解决以上两个需求,我想通过多进程来实现,但是没有具体的实现方式。

    1. 需要有一个能实现的最简示例。
    2. 如果通过 Nginx 代理,Gunicorn 的 -w 参数还需要设置 cpu *2 +1 的数量吗

    其他补充

    用 Gunicorn 启动服务后,在 flask 的 路由函数里面开启了多进程(通过 ProcessPoolExecutor),控制台会提示有些进程被忽略掉,而且有些进程没有运行,好像有些进程也被阻塞了。
    然后看到 multiprocessing.Pool 可以直接 terminate 终止进程池,但是有个限制

    注意 start() 、join() 、is_alive() 、terminate() 和 exitcode 方法只能由创建进程对象的进程调用。

    18 条回复    2022-09-03 12:01:11 +08:00
    cyberpoint
        1
    cyberpoint  
    OP
       2022-08-31 18:19:46 +08:00
    对咯,这个服务用的 时候,不会用太多用户,一般就 三四人用户同时在用。
    Kobayashi
        2
    Kobayashi  
       2022-08-31 18:38:57 +08:00 via Android
    为什么不用 rq 或者 celery ?
    Kobayashi
        3
    Kobayashi  
       2022-08-31 18:43:01 +08:00 via Android
    实现不了。
    cyberpoint
        4
    cyberpoint  
    OP
       2022-08-31 19:04:52 +08:00
    @Kobayashi 感谢,我也是刚刚接触 Python ,处于边学边用的状态。我去看看你说的 rq 和 celery 话说推荐用其中哪个呢。
    svtter
        5
    svtter  
       2022-08-31 19:45:57 +08:00
    长耗时任务,应该用异步跑。
    cyberpoint
        6
    cyberpoint  
    OP
       2022-08-31 20:07:53 +08:00
    @svtter 是指 asyncio 吗。 这个应该不适合我这里。我这个 是计算密集型
    LindsayZhou
        7
    LindsayZhou  
       2022-08-31 20:23:08 +08:00
    @cyberpoint #6
    asyncio 可以用多线程跑: https://docs.python.org/3/library/asyncio-task.html#running-in-threads

    然后还有个 Task 类可以用来管理 Coroutines 的生命周期: https://docs.python.org/3/library/asyncio-task.html#task-object

    我只是看到过,没用过,只能帮你把文档找出来
    ch2
        8
    ch2  
       2022-08-31 20:23:41 +08:00
    这种需求,应该用消息队列来做,多进程做起来耦合挺严重的
    huangzhiyia
        9
    huangzhiyia  
       2022-08-31 20:26:36 +08:00 via Android
    用 celery +redis 吧,符合你所有需求。
    raycool
        10
    raycool  
       2022-08-31 20:30:40 +08:00
    这种可以使用 tornado + redis + concurrent.futures.ProcessPoolExecutor 来做
    elboble
        11
    elboble  
       2022-08-31 20:53:48 +08:00 via Android
    Celery 吧,应该比较合适
    LindsayZhou
        12
    LindsayZhou  
       2022-08-31 20:58:00 +08:00
    svtter
        13
    svtter  
       2022-08-31 21:20:40 +08:00
    1. 异步任务是那些被引擎放在一边,不进入主线程、而进入任务队列的任务。
    2. 任务队列可以用 celery + redis 来做。
    3. WEB 应用系统是负责接收前端请求,并进行简单处理的软件系统。
    4. 计算型的程序逻辑,应根据对算力的要求,另外开启进程或者采用另外的服务器来做。
    svtter
        14
    svtter  
       2022-08-31 21:23:02 +08:00
    5. 使用 celery 的话,celery worker 就是`另外的进程`
    6. celery worker 如果不在本机,就是`另外的服务器`
    lambdaq
        15
    lambdaq  
       2022-08-31 21:25:03 +08:00
    就问一个简单问题,如果 2 个机器跑你这个 web 服务

    A 机器执行了 /task/create 开始多进程

    B 机器接到了 /task/close 怎么办?
    imycc
        16
    imycc  
       2022-08-31 21:33:07 +08:00
    gunicorn 只负责做接收 web 请求,计算任务通过 celery 的 worker 去执行,去看看 celery 的官网教程就好。中间消息传递的部分,需要用消息队列或者 redis ( mysql 其实也行)

    至于停止任务,可以用 celery 的[revoke 方法]( https://docs.celeryq.dev/en/stable/userguide/workers.html#revoke-revoking-tasks) 创建任务之后会得到一个 task_id ,存起来或者返回给前端。然后用这个 task_id 取消掉任务就行。

    但杀掉正在运行的进程,只对 prefork 和 eventlet 类型的 worker 有效,因为线程和协程没法单独杀掉。如果你用线程 /协程创建的 worker ,需要引入额外的机制,让他们每隔一段时间就检查外部的标志位,判断是否要继续运行。
    ospider
        17
    ospider  
       2022-08-31 22:30:29 +08:00
    千万别用 celery ,bug 一大堆,坑你没商量。自己拿 redis 封装个消息队列很简单的,别想太复杂。
    subjadeites
        18
    subjadeites  
       2022-09-03 12:01:11 +08:00 via Android
    土一点甚至可以把计算部分单独封一个入口,然后调命令启动获取 pid ,在 redis 里存 task 标识符和 pid ,收到 close 直接 kill(
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5651 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 08:08 · PVG 16:08 · LAX 00:08 · JFK 03:08
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.