【问题标题】:python multiprocessing why much slowerpython多处理为什么慢得多
【发布时间】:2014-11-15 01:11:10
【问题描述】:

对于从列表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.close()pool.join(),但它不起作用。

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。

谢谢!

【问题讨论】:

  • src_list 有多大?它里面的数据结构有多大?
  • 另外,我不确定你说使用 t = time.time() ; print time.time() = t` 不起作用是什么意思。什么不完全有效?
  • 关于时间测量,可以使用timeit模块。
  • timeit 不适用于我的情况,或者我用错了。我已经更新了我的问题。

标签: python multiprocessing


【解决方案1】:

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

def NothingButAPickle(elem):
    return elem

如果您在单个进程中循环您的 src_list,这应该非常快,因为 Python 只需在内存中为列表中的每个对象制作一份副本。相反,如果您与多处理程序包并行调用此函数,则它必须 (1) 腌制每个对象以将其作为字符串从主进程发送到子进程 (2) 对子进程中的每个对象进行解腌以从字符串表示形式变为内存中的对象 (3) 腌制该对象以将其返回给以字符串表示的主进程,然后 (4) 解腌该对象以将其表示在主进程的内存中。在没有看到您的数据或实际函数的情况下,如果您传递的对象非常大和/或函数实际上不是计算密集型,那么这种开销成本通常只会超过多处理收益。

【讨论】:

  • 明白你的意思,迈克尔。这是否意味着我应该使用多线程?而且,我认为 my_func 需要的时间远远超过额外的挑选开销,因此多处理不应该慢得多。
  • 因为 python 中的多线程对于 cpu 绑定的任务实际上仅限于一个核心,所以它会更慢。查看有关 GIL 的信息。
  • @fetcher 内存中的列表有多大/列表中的每个对象有多大?在单个进程中对函数的一次调用需要多长时间? Max 是对的,多线程仍然只使用单核。它将加速非 CPU 绑定的任务,例如网页抓取,因为它不会在请求来自另一个站点的另一个链接之前等待该站点的响应。但是多线程只使用一个进程,当该进程忙于使用 CPU 时,它也正忙于使用 CPU。
  • 原来我在src_list的单个对象中存储了太多。我尝试减小 src_list 中对象的大小。现在它运行得更快(320 秒),但仍然比直接方法慢。那么在我的情况下并行运行的最佳策略是什么?我应该事先拆分 src_list 并在单独的进程中运行每个部分吗? chunksize 选项不做同样的事情吗?
猜你喜欢
  • 2014-08-14
  • 1970-01-01
  • 1970-01-01
  • 2015-10-11
  • 2015-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多