Celery 任务调用 multiprocessing 库时如何并行运行?
结论
Celery 不会自动把一个任务拆成多个 Celery 任务,也不会把任务内部通过 multiprocessing 创建的进程分派给其他 Celery worker。外部库创建的进程由它在当前 worker 主机上管理。
如果外部库会创建子进程,而你又无法修改它的实现,可以尝试让 Celery 使用 threads 或 solo pool,再由外部库负责进程级并行。这种配置仍可能用到多个 CPU 核心:Celery 的线程池并发运行任务,multiprocessing 创建的子进程也可以使用多个核心。前提是外部库能在目标操作系统和进程启动方式下正常创建子进程。
为什么 prefork 可能失败
Celery 的 prefork pool 会在 worker 子进程中执行任务。Python multiprocessing 不允许 daemon 进程再创建子进程,因此可能报错:
daemonic processes are not allowed to have children
如果外部库在任务执行时调用 multiprocessing 创建进程,就可能触发这个限制。是否报错取决于 Celery 使用的 pool、运行环境和库的实现。可以先检查完整 traceback,确认错误是否发生在创建子进程时。
可尝试的运行方式
使用 threads pool
celery -A your_app worker -P threads --concurrency=4
这里的 --concurrency 限制同时运行的 Celery 任务数,不限制外部库创建的子进程数。每个任务仍可能通过 mp_func(n_proc) 启动多个进程。
使用 solo pool
如果希望 Celery 一次只运行一个任务,可以尝试:
celery -A your_app worker -P solo
任务仍由外部库在 worker 所在主机上创建进程。solo 不会并行运行多个 Celery 任务,适合先验证调用路径,或用于并发要求较低的情况。能否创建子进程仍需在目标环境中确认。
计算总并发与资源
使用 threads 时,Celery 的任务并发数会和任务内部的进程数叠加。例如,同时运行 4 个任务,每个任务最多创建 3 个子进程,就可能同时有多组工作进程运行。实际进程数取决于外部库的实现。应限制 Celery 的 --concurrency 和传给 mp_func 的进程数,并留意 CPU、内存和进程数上限,避免并发过多。
需要跨 worker 分发时
multiprocessing 不会把单个计算任务的不同部分分发到多台机器。通常需要把计算拆成多个可独立执行的 Celery 任务,再汇总结果;也可以让外部库使用支持跨机器调度的执行后端。前一种方式需要调整任务边界,后一种则取决于外部库支持的接口。
如果不能修改外部库,且只需在单台机器上利用多个核心,可以先尝试 threads 或 solo pool,并在目标环境中验证子进程能否启动。若要把同一任务的工作量分配到不同 worker,就需要通过 Celery 任务编排或其他分布式执行机制来实现。
备注:内容仅供参考。
