对于从列表src_list到dest_list的map任务,len(src_list)的级别为数千:
def my_func(elem):
# some complex work, for example a minimizing task
return new_elem
dest_list[i] = my_func(src_list[i])
我使用multiprocessing.Pool
pool = Pool(4)
# took 543 seconds
dest_list = list(pool.map(my_func, src_list, chunksize=len(src_list)/8))
# took 514 seconds
dest_list = list(pool.map(my_func, src_list, chunksize=4))
# took 167 seconds
dest_list = [my_func(elem) for elem in src_list]
我很困惑。有人可以解释为什么多处理版本运行得更慢吗?
我想知道选择chunksize和两者之间的选择需要考虑什么 多线程和多进程,特别是对我的问题。此外,目前,我测量时间 总结在my_func方法中花费的所有时间,因为直接使用
t = time.time()
dest_list = pool.map...
print time.time() - t
不起作用。但是,在here中,文档说map()阻塞,直到结果准备好,它似乎与我的结果不同。有没有其他方式而不是简单地总结时间?我尝试使用 pool.join() pool.close(),但这不起作用。
src_list的长度大约为2000. time.time() - t不起作用,因为它没有总结pool.map中my_func所花费的所有时间。当我使用timeit时,奇怪的事情发生了。
def wrap_func(src_list):
pool = Pool(4)
dest_list = list(pool.map(my_func, src_list, chunksize=4))
print timeit("wrap_func(src_list)", setup="import ...")
它遇到了
OS Error Cannot allocate memory
猜猜我用错误的方式使用了timeit ......
我在Ubuntu 14.04下使用python 2.7.6。
谢谢!
答案 0 :(得分:5)
多处理需要在进程之间传递数据的开销,因为进程不共享内存。必须对进程之间传递的任何对象进行pickle(表示作为字符串)并进行depickled。这包括传递给列表src_list
中的函数的对象以及返回到dest_list
的任何对象。这需要时间。为了说明这一点,您可以尝试在单个过程中并行地同时计算以下功能。
def NothingButAPickle(elem):
return elem
如果你在一个进程中遍历src_list
,这应该非常快,因为Python只需要在内存列表中制作每个对象的一个副本。相反,如果你将这个函数与多处理包并行调用,它必须(1)pickle每个对象将它从主进程发送到子进程作为字符串(2)去除子进程中的每个对象,从字符串表示到内存中的一个对象(3)pickle对象将其返回到表示为字符串的主进程,然后(4)去除对象以在主进程的内存中表示它。在没有看到您的数据或实际功能的情况下,如果您传递的对象非常大和/或该功能实际上不是计算密集型,则此开销成本通常仅超过多处理增益。