在 python3 中,我对multiprocessing
领域并不陌生,因此,如果以前曾问过这个问题,我感到抱歉。我有一个脚本,该脚本从N个元素的列表中对每个元素运行整个分析,并将每个映射到不同的进程。
我知道这是次优的,实际上我想提高多处理效率。我使用map()
将每个进程运行到Pool()
中,其中可以包含用户通过命令行参数指定的尽可能多的进程。
代码如下:
max_processes = 7
# it is passed by command line actually but not relevant here
def main_function( ... ):
res_1 = sub_function_1( ... )
res_2 = sub_function_2( ... )
if __name__ == '__main__':
p = Pool(max_processes)
Arguments = []
for x in Paths.keys():
# generation of the arguments
...
Arguments.append( Tup_of_arguments )
p.map(main_function, Arguments)
p.close()
p.join()
如您所见,我的进程调用了一个main函数,而main函数又依次调用了许多其他函数。现在,每个sub_functions都是可多重处理的。我可以将那些子功能中的进程映射到主程序运行所在的同一个池中吗?
答案 0 :(得分:1)
不,你不能。
该池(几乎)在工作进程中不可用。这取决于用于池的start method。
生成
一个新的Python解释器进程将启动并导入模块。由于在该过程中__name__
是'__mp_main__'
,因此__name__ == '__main__'
块中的代码不会执行,并且工作线程中不存在任何池对象。
叉子
父进程的内存空间被复制到子进程的内存空间。这实际上会导致每个工作程序的内存空间中存在一个Pool
对象。
但是,该池不可用。在执行池的__init__
期间创建了工作程序,因此,在对工作程序进行分叉时,池的初始化不完整。工作进程中池的副本没有运行用于管理工作进程,任务和结果的线程。无论如何,线程都不会通过fork
进入子进程。
此外,由于在初始化期间创建了工作程序,因此该对象尚未分配给池对象。尽管它确实潜伏在工作人员的内存空间中,但是却没有任何处理。它不会通过globals()
显示;我只能通过gc.get_objects()
找到它:<multiprocessing.pool.Pool object at 0x7f75d8e50048>
无论如何,该池对象是主进程中对象的副本。
叉子服务器
我无法测试此启动方法
要解决您的问题,您可以可以在主进程中摆弄队列和队列处理程序线程,以从工作者中发回任务并将其委派给池,但是我能想到的所有方法看起来很笨拙。
如果您努力采用它来在池中进行处理,您将很可能最终获得更多可维护的代码。
顺便说一句:我不确定允许用户通过命令行传递工人数量是否是一个好主意。我建议至少通过os.cpu_count()
赋予该值一个上限。