我的名单很大。我要处理每个项目。我想细分列表并在不同的CPU上处理每个细分。我正在使用pathos多处理库。我创建了以下函数:
def map_list_in_segments (l, f):
cpus = max(1, int(cpu_count() / 2) - 1)
seg_length = int(len(l) / cpus)
segments = [l[x:x+seg_length] for x in range(0,len(l),seg_length)]
pool = Pool(nodes=cpus)
mapped_segments = pool.map(lambda seg: f(seg), segments)
return (sg for seg in mapped_segments for sg in seg)
它返回正确的结果,并使用所有(或几乎所有)CPU。但是,对返回的列表进行迭代会导致意外地消耗大量内存。
起初,我返回的是列表理解功能。我将其切换为生成器,希望减少内存消耗,但是并没有任何改善。
基于评论的更新:
我不知道imap
和uimap
,并且它们会自动对输入列表进行分块。我尝试了uimap
,但是看到CPU利用率很低并且运行时间很长。其中一个进程的CPU利用率很高。我认为正在发生的事情是有很多酸洗。我要传递的f
在闭包中有一个大对象。使用ProcessingPool方法(map
,imap
,uimap
)时,需要为列表中的每个元素腌制该对象。我怀疑这是一个非常繁忙的过程正在做的事情。腌制限制了其他过程。
如果是这样,这说明了为什么我的手动分段会导致CPU使用率显着提高:大型对象每个分段只需要被酸洗一次,而不是每个项目都被酸洗一次。
然后我尝试在uimap
中使用map_list_in_segments
,希望减少内存消耗,但这没有发生。调用该方法并迭代结果的代码如下:
segments = multiprocessing.map_list_in_segments(l, lambda seg: process_segment(seg, large_object_needed_for_processing))
for seg in segments:
for item in seg:
# do something with item
我对生成器的(有限的)理解是,遍历段的第一个for
循环应在迭代时从内存中释放每个段。如果是这样,似乎大的内存使用量就是process_segment
方法的返回值的酸洗。我没有返回大量数据(每个项目大约1K字节),并且正在使用的l
的大小为6000个项目。不知道为什么要消耗5GB的内存。
答案 0 :(得分:0)
multiprocessing
的问题在于,进程之间的通信非常昂贵。如果结果的大小等于输入的大小,则可能会花费大部分时间来腌制和取消腌制数据,而不是做任何有用的事情。这取决于f
的价格,但是最好不要在这里使用multiprocessing
。
答案 1 :(得分:0)
一些进一步的测试表明,酸洗不是问题。我在for item in seg
中所做的处理是构造其他消耗大量内存的对象。
从此练习中获得的见解和聪明的评论者:
map
,imap
,uimap
)自动将列表分块。f
,则可能会发现手动对列表进行分块(如上)可节省大量酸洗并提高CPU利用率。imap
和uimap
可以大大减少内存使用。