如何为CPU密集型任务执行加权公平任务队列(在Python中)?

时间:2016-12-05 20:57:59

标签: python queue multiprocessing task

问题

我们对用户输入的地理数据进行了多次计算(称为“系统”)。有时一个系统需要10个位置来进行计算,有时需要1000+。一个位置需要大约1秒来计算,希望我们可以在未来加快这一速度。我们目前通过在Celery工作者中使用多处理Pool(来自billiard)来完成此操作。这是因为它100%利用所有核心,但有两个问题:

  • 当达到最大打开文件限制时,会导致工作人员挂起(pipe,这可能会导致工作人员挂起(已调查,但在超过一天的时间内未找到解决方案)工作)
  • 我们无法在多台计算机上进行计算。

要解决这些问题,我可以将每个计算作为单独的Celery任务运行。但是,我们还希望为用户“公平”安排这些计算,以便:

在小型系统(例如< 50个位置)上工作的用户不必等到大型系统(> 1000个位置)完成。系统越大,等待时间越长对用户的影响越小(无论如何他们正在做其他事情,并且可以得到通知)。所以这类似于Weighted fair queueing

我无法找到实现优先级排序的分布式任务运行器。我错过了一个吗?我查看了CeleryRQHueyMRQPulsar Queue等等,以及数据处理LuigiPinball等管道,但似乎没有人能够轻松启用此功能。

其中大多数建议通过为更高优先级的队列添加更多工作人员来创建优先级。然而,这不会起作用,因为工人会开始争夺CPU时间。 (RQ通过清空首先传入队列的完整,然后再转到下一个)来做到不同。

建议的架构

我想象的是运行一个多处理程序,每个CPU都有一个进程,以WFQ方式从多个Redis列表中获取,每个列表都是一个特定的队列。

这是正确的方法吗?当然,要使队列配置成为动态的,还有很多工作要做(例如,还要将它存储在Redis中,并在每次运行时重新加载它处理过的任务),并让事件监控能够获得洞察力。

其他想法:

  • 每个任务需要大约3MB的数据,来自Postgres,对于系统中的每个位置(或至少每100个位置)都是相同的。使用当前方法,它驻留在共享内存中,并且每个进程都可以快速访问它。我可能不得不在每台机器上设置一个本地Redis实例来缓存这些数据,因此不是每个进程都会反复获取它。
  • 我一直在关注ZeroMQ,它有很多诱人的可能性,但除了监控之外,它似乎不太合适。或者我错了吗?
  • 更有意义的是:将每个工作人员作为一个单独的程序运行,并使用诸如管理员或启动单个程序来管理它,为每个CPU分配一个子程序(不需要CPU计数配置),也可能监视器它的孩子陷入困境?
  • 我们已经运行了RabbitMQ和Redis,所以我也可以使用RMQ作为队列。在我看来,使用RMQ获得的唯一好处是可以通过使用确认来减少工作人员崩溃的任务,但代价是使用更困难的库/复杂协议。

还有其他建议吗?

0 个答案:

没有答案