大佬们问下 Python 多进程的问题
发送一个请求 /task/create 开启了一个长耗时计算密集型任务。在这个任务运行的过程中,可以发送另一个请求 /task/close 来关闭这个任务。
用 flask 建立了一个项目,通过 Gunicorn + Gevent 在 centos7 上部署了服务(尚未通过 Nginx 走代理)。
为了解决以上两个需求,我想通过多进程来实现,但是没有具体的实现方式。
用 Gunicorn 启动服务后,在 flask 的 路由函数里面开启了多进程(通过 ProcessPoolExecutor),控制台会提示有些进程被忽略掉,而且有些进程没有运行,好像有些进程也被阻塞了。
然后看到 multiprocessing.Pool 可以直接 terminate 终止进程池,但是有个限制
注意 start() 、join() 、is_alive() 、terminate() 和 exitcode 方法只能由创建进程对象的进程调用。
1
cyberpoint OP 对咯,这个服务用的 时候,不会用太多用户,一般就 三四人用户同时在用。
|
2
Kobayashi 2022-08-31 18:38:57 +08:00 via Android
为什么不用 rq 或者 celery ?
|
3
Kobayashi 2022-08-31 18:43:01 +08:00 via Android
实现不了。
|
4
cyberpoint OP @Kobayashi 感谢,我也是刚刚接触 Python ,处于边学边用的状态。我去看看你说的 rq 和 celery 话说推荐用其中哪个呢。
|
5
svtter 2022-08-31 19:45:57 +08:00
长耗时任务,应该用异步跑。
|
6
cyberpoint OP @svtter 是指 asyncio 吗。 这个应该不适合我这里。我这个 是计算密集型
|
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 我只是看到过,没用过,只能帮你把文档找出来 |
8
ch2 2022-08-31 20:23:41 +08:00
这种需求,应该用消息队列来做,多进程做起来耦合挺严重的
|
9
huangzhiyia 2022-08-31 20:26:36 +08:00 via Android
用 celery +redis 吧,符合你所有需求。
|
10
raycool 2022-08-31 20:30:40 +08:00
这种可以使用 tornado + redis + concurrent.futures.ProcessPoolExecutor 来做
|
11
elboble 2022-08-31 20:53:48 +08:00 via Android
Celery 吧,应该比较合适
|
12
LindsayZhou 2022-08-31 20:58:00 +08:00
|
13
svtter 2022-08-31 21:20:40 +08:00
1. 异步任务是那些被引擎放在一边,不进入主线程、而进入任务队列的任务。
2. 任务队列可以用 celery + redis 来做。 3. WEB 应用系统是负责接收前端请求,并进行简单处理的软件系统。 4. 计算型的程序逻辑,应根据对算力的要求,另外开启进程或者采用另外的服务器来做。 |
14
svtter 2022-08-31 21:23:02 +08:00
5. 使用 celery 的话,celery worker 就是`另外的进程`
6. celery worker 如果不在本机,就是`另外的服务器` |
15
lambdaq 2022-08-31 21:25:03 +08:00
就问一个简单问题,如果 2 个机器跑你这个 web 服务
A 机器执行了 /task/create 开始多进程 B 机器接到了 /task/close 怎么办? |
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 ,需要引入额外的机制,让他们每隔一段时间就检查外部的标志位,判断是否要继续运行。 |
17
ospider 2022-08-31 22:30:29 +08:00
千万别用 celery ,bug 一大堆,坑你没商量。自己拿 redis 封装个消息队列很简单的,别想太复杂。
|
18
subjadeites 2022-09-03 12:01:11 +08:00 via Android
土一点甚至可以把计算部分单独封一个入口,然后调命令启动获取 pid ,在 redis 里存 task 标识符和 pid ,收到 close 直接 kill(
|