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

Tin*_*ino 5 python queue task multiprocessing

问题

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

  • 有一些缠绵的连接(pipe可能与子进程有关)会导致工作人员在达到最大打开文件数限制时挂起(已调查,但在工作一天以上后仍未找到解决方案)
  • 我们无法将计算分散到多台计算机上。

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

使用小型系统(例如<50个位置)的用户不必等到大型系统(> 1000个位置)完成。系统越大,对用户而言增加的等待时间就越少(无论如何,他们正在做其他事情,并且可以获得通知)。因此,这类似于加权公平排队

我找不到能够实现这种优先级排序的分布式任务运行器。我想念一个吗?我查看了CeleryRQHueyMRQPulsar Queue等,以及诸如LuigiPinball之类的数据处理管道,但似乎没有一个能够轻松实现这一点。

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


拟议的架构

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

这是正确的方法吗?当然,要使队列配置具有动态性(例如,也将其存储在Redis中,并在每对已处理的任务中重新加载它),并进行事件监视以获取洞察力,还有很多工作要做。

其他想法:

  • 每个任务需要大约3MB的数据,这些数据来自Postgres,这对于系统中的每个位置(或至少每100个位置中的两个位置)都是相同的。使用当前方法,它位于共享内存中,每个进程都可以快速访问它。我可能必须在每台计算机上设置一个本地Redis实例以将该数据缓存到其中,因此并非每个进程都会一次又一次地获取数据。
  • 我一直在跟ZeroMQ交流,它有很多诱人的可能性,但是除了监视之外,它似乎不太适合。还是我错了?
  • 更有意义的是:将每个工作程序作为单独的程序运行,并使用管理程序进行管理,或启动一个程序,为每个CPU派生一个子代(无需配置CPU计数),并且可能还监视其子代是否卡住的过程?
  • 我们已经运行过RabbitMQ和Redis,因此我也可以将RMQ用于队列。在我看来,使用RMQ唯一获得的好处是,通过使用确认,不会在工作人员崩溃时丢失任务,而以使用更困难的库/复杂协议为代价。

还有其他建议吗?