你好,我有一个像
这样的多处理程序#this is pseudocode-ish
def worker(queue, context):
set_context(context) #set global context within worker
while queue.qsize() > 0:
process(queue.get(False))
pool = multiprocessing.Pool(20, worker, (queue, global_context))
pool.close()
pool.join()
问题是global context
是一个非常重的对象,所以产生每个单独的过程(酸洗/去除)需要一段时间。所以我发现的是,对于较短的队列,整个队列由前几个生成的进程处理,然后程序的其余部分卡在其余的进程中,这不可避免地无所事事,因为队列中没有任何东西。例如。每个进程需要1秒生成,但队列在2秒内处理 - 所以前两个进程在2-3秒内完成队列,然后程序的其余部分需要17秒来生成其余队列。
当队列为空时,有没有办法杀死其余的进程?或者更灵活的方式来设置池的进程数 - 例如只在需要时才生成另一个进程?
由于
答案 0 :(得分:6)
无法使用multiprocessing.Pool
动态生成流程。如果您想要这种类型的行为,您需要自己修改它。
对于关机,一种方法是使用multiprocessing.Pool.terminate
方法。但它可能会等待所有worker
完成初始化。
您还可以在工作完成后直接杀死所有工作人员。我认为他们是_pool
字段,其中包含您可以强制终止的所有工作人员Process
。请注意,如果不打算在外部处理,这可能会导致一些奇怪的行为。您必须确保正确清理所有管理thread
,这可能很棘手。
您的设计选择非常不寻常。您正在复制call_queue
。实际上,Pool
应该自己处理通信,而您不需要额外的queue
。如果所有广告都位于task_list
且需要由process_task
处理,您可以执行类似
#this is pseudocode-ish
def init(queue, context):
set_context(context) # set global context within worker
pool = multiprocessing.Pool(20, init, (global_context,))
res = pool.map(process_task, task_list)
pool.terminate()
pool.join()
这样可以避免破坏Pool
设置并且可能更有效。
最后,如果您打算多次重用池,并且global_context不会更改,则可以考虑使用loky
。 (免责声明:我是这个项目的维护者之一)。
这允许您在程序中多次重用一个工作池,而无需重新设置所有内容。
一个问题是initializer
没有concurrent.futures
,因为它遵循initializer
的API,但multiprocessing.Barrier
可以使用max_workers
完成并提交initializer
初始化工作。这将确保initializer
的每个作业都由一个工作人员运行,并且所有工作人员都运行{{1}}。