我正在使用Celery 对我制作的 CGI 应用程序中的作业进行排队。按照我的设置方式,Celery 通过设置CELERYD_CONCURRENCY = 1
or使每个作业一次运行一个或两个= 2
(因此它们不会拥挤处理器或因内存消耗而崩溃)。多亏了我在 StackOverflow 上得到的建议,队列工作得很好。
这些作业中的每一个都需要相当长的时间(大约 30 分钟串行),但具有令人尴尬的并行性。出于这个原因,我Pool.map
习惯于拆分它并并行完成工作。它在命令行中运行良好,我使用新的多核芯片获得了大约 5 分钟的运行时间。
不幸的是,有一些限制不允许守护进程拥有子进程,当我在 CGI 队列中运行花哨的并行化代码时,我收到此错误:
AssertionError: 守护进程不允许有子进程
我注意到其他人也有类似的问题,但我找不到不需要完全放弃Pool.map
并制作更复杂的线程代码的答案。
这里合适的设计选择是什么?我可以使用我的 Celery 队列轻松运行我的串行作业。我还可以在没有队列的情况下运行我更快的并行化作业。我应该如何解决这个问题,是否可以获得我想要的(队列和每个作业并行化)?
我有几个想法(有些很老套):
- 发送到 Celery 队列的作业只是调用命令行程序。该程序可以随意使用 Pool,然后将结果数字和数据保存到文件中(就像现在一样)。
缺点:我将无法检查作业的状态或查看它是否成功终止。此外,来自 CGI 的系统调用可能会导致安全问题。 - 显然,如果队列中的作业非常多,我可以充分利用 CPU 资源(通过设置 CELERYD_CONCURRENCY = 6 左右);这将允许许多人同时“排在队列的最前面”。
缺点:每个工作都会在队列最前面花费大量时间;如果队列未满,则不会有加速。此外,许多部分完成的作业将同时存储在内存中,使用更多的 RAM。 - 使用 Celery 的 @task 在子作业中并行化。然后,我不会设置 CELERYD_CONCURRENCY = 1,而是将其设置为 6(或者我希望一次允许在内存中的许多子作业)。
缺点:首先,我不确定这是否会成功避免“任务中的任务”问题。但是,队列位置的概念可能会丢失,许多部分完成的作业可能会立即进入内存。 - 也许有一种方法可以调用 Pool.map 并指定线程是非守护线程的?或者也许我可以使用更轻量级的东西来代替 Pool.map?这类似于对另一个开放的 StackOverflow 问题采取的方法。另外,我应该注意,我通过 Pool.map 利用的并行化类似于线性代数,并且没有进程间通信(每个都独立运行并返回其结果而不与其他人交谈)。
- 扔掉 Celery 并使用 multiprocessing.Queue。那么也许有一些方法可以为我使用的每个线程使用相同的“线程深度”(即,也许所有线程都可以使用同一个池,避免嵌套)?
提前非常感谢。