python多处理为什么慢得多

时间:2014-11-13 15:00:08

标签: python multiprocessing

对于从列表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。

谢谢!

1 个答案:

答案 0 :(得分:5)

多处理需要在进程之间传递数据的开销,因为进程不共享内存。必须对进程之间传递的任何对象进行pickle(表示作为字符串)并进行depickled。这包括传递给列表src_list中的函数的对象以及返回到dest_list的任何对象。这需要时间。为了说明这一点,您可以尝试在单个过程中并行地同时计算以下功能。

def NothingButAPickle(elem):
    return elem

如果你在一个进程中遍历src_list,这应该非常快,因为Python只需要在内存列表中制作每个对象的一个​​副本。相反,如果你将这个函数与多处理包并行调用,它必须(1)pickle每个对象将它从主进程发送到子进程作为字符串(2)去除子进程中的每个对象,从字符串表示到内存中的一个对象(3)pickle对象将其返回到表示为字符串的主进程,然后(4)去除对象以在主进程的内存中表示它。在没有看到您的数据或实际功能的情况下,如果您传递的对象非常大和/或该功能实际上不是计算密集型,则此开销成本通常仅超过多处理增益。