我使用一个简单的RabbitMQ队列将任务分配给工作进程。每个工作进程使用一个multiprocessing
实例池同时处理多个任务,以尽可能多地使用内存和CPU。
问题是,某些任务占用的RAM比其他任务多得多,因此如果启动多个实例,则工作进程会崩溃。但是当工作人员正在处理RAM密集型任务时,我希望能够处理其他RAM较少的任务,以便使用其余的CPU。
一个想法是使用多个队列或主题,但我想知道推荐的方法是什么。我可以在崩溃过程中捕获内存错误吗?
解决这个问题的正确方法是什么?
[更新后的更新]
整个系统将由多个多核机器组成,但在每个多核机器上只运行一个工作程序,它创建了与核心一样多的多处理实例。不同的机器应该彼此独立,除非它们从同一队列中获取任务。
答案 0 :(得分:1)
我认为尝试捕获并从OOM错误中恢复将是非常困难的,如果不是不可能的话。您需要一个运行的线程或进程来持续监视内存使用情况,当它检测到它太高时,确实......究竟是什么?杀死正在处理任务的进程?试图暂停它(如果可能的话;它可能不依赖于你的任务正在做什么)。即使这样,暂停它也不会释放任何记忆。您必须释放内存并在安全时重新启动任务,这意味着您必须重新排队,确定其安全性等等。
我建议尝试完全避免它,而不是试图检测并从问题中恢复。创建两个队列和两个池。一个队列/池用于高内存任务,另一个队列/池用于低内存任务。高内存池中只有一个进程,因此它将仅限于同时运行一个任务,这样可以节省内存。低内存队列将有multiprocessing.cpu_count() - 1
个进程,允许您在两个池中保持CPU饱和。
这种方法的一个潜在问题是,如果在耗尽低内存任务的情况下耗尽高内存队列,那么您将浪费其中一个CPU。您可以以非阻塞方式(或使用超时)从高内存队列中处理此消耗,这样,如果当您准备好使用任务时高内存队列为空,则可以获取低 - 记忆任务而不是。然后,当您完成处理后,再次检查高内存队列。
这样的事情:
import multiprocessing
# hi_q and lo_q are placeholders for whatever library you're using to consume from RabbitMQ
def high_mem_consume():
while True:
task = hi_q.consume(timeout=2)
if not task:
lo_q.consume(timeout=2)
if task:
process_task(task)
def low_mem_consume():
while True:
task = lo_q.consume() # Blocks forever
process_task(task)
if __name__ == "__main__":
hi_pool = multiprocessing.Pool(1)
lo_pool = multiprocessing.Pool(multiprocessing.cpu_count() - 1)
hi_pool.apply_async(high_mem_consume)
lo_pool.apply_async(lo_mem_consume)