【问题标题】:Why is multiprocessing.Pool.map slower than builtin map?为什么 multiprocessing.Pool.map 比内置地图慢?
【发布时间】:2012-02-28 11:37:32
【问题描述】:
import multiprocessing
import time
from subprocess import call,STDOUT
from glob import glob
import sys


def do_calculation(data):
    x = time.time()
    with open(data + '.classes.report','w') as f:
        call(["external script", data], stdout = f.fileno(), stderr=STDOUT)
    return 'apk: {data!s} time {tim!s}'.format(data = data ,tim = time.time()-x)


def start_process():
    print 'Starting', multiprocessing.current_process().name

if __name__ == '__main__':

    inputs = glob('./*.dex')


    builtin_outputs = map(do_calculation, inputs)
    print 'Built-in:'
    for i in builtin_outputs:
        print i

    pool_size = multiprocessing.cpu_count() * 2
    print 'Worker Pool size: %s' % pool_size
    pool = multiprocessing.Pool(processes=pool_size,
                                initializer=start_process,
                                )
    pool_outputs = pool.map(do_calculation, inputs)
    pool.close() # no more tasks
    pool.join()  # wrap up current tasks

    print 'Pool output:'
    for i in pool_outputs:
        print i

令人惊讶的是,builtin_outputs 的执行时间比 pool_outputs 更快:

Built-in:
apk: ./TooDo_2.0.8.classes.dex time 5.69289898872
apk: ./TooDo_2.0.9.classes.dex time 5.37206411362
apk: ./Twitter_Client.classes.dex time 0.272782087326
apk: ./zaTelnet_Light.classes.dex time 0.141801118851
apk: ./Temperature_Converter.classes.dex time 0.270312070847
apk: ./Tipper_1.0.classes.dex time 0.293262958527
apk: ./XLive.classes.dex time 0.361288070679
apk: ./TwitterDroid_0.1.2_alpha.classes.dex time 0.381947040558
apk: ./Universal_Conversion_Application.classes.dex time 0.404763936996

Worker Pool size: 8

Pool output:
apk: ./TooDo_2.0.8.classes.dex time 5.72440505028
apk: ./TooDo_2.0.9.classes.dex time 5.9017829895
apk: ./Twitter_Client.classes.dex time 0.309305906296
apk: ./zaTelnet_Light.classes.dex time 0.374011039734
apk: ./Temperature_Converter.classes.dex time 0.450366973877
apk: ./Tipper_1.0.classes.dex time 0.379780054092
apk: ./XLive.classes.dex time 0.394504070282
apk: ./TwitterDroid_0.1.2_alpha.classes.dex time 0.505702018738
apk: ./Universal_Conversion_Application.classes.dex time 0.512043952942

如何解释这种性能差异?

【问题讨论】:

  • 您是否把问题的标题弄错了? :)
  • 是的,这很令人困惑。
  • 天哪。 Chrome 存储了我之前不完整的问题。对不起:|

标签: python multiprocessing performance-testing


【解决方案1】:

如果“外部脚本”所涉及的工作负载的 IO 量大到足以使您的硬盘饱和,那么并行运行多个副本只会减慢您的速度,因为从多个文件中读取会导致额外的寻道。

如果您的 CPU 饱和并且没有多个 CPU 内核可用,情况也是如此。

【讨论】:

  • 这是否意味着我最好顺序运行它而不是并行运行?
  • 嗯,它更快......所以是的。 :)
【解决方案2】:
def do_calculation(data):
    x = time.time()
    with open(data + '.classes.report','w') as f:
        call(["external script", data], stdout = f.fileno(), stderr=STDOUT)
    return 'apk: {data!s} time {tim!s}'.format(data = data ,tim = time.time()-x)

您正在测量执行单个任务所需的时间。如果您并行运行任务,则每个单独的任务都不会变短。相反,它们都同时运行。换句话说,您测量这个错误,您应该计算所有任务的总时间,而不是单独计算每个任务。

缓慢可能是因为同时运行各种任务会相互干扰,因此任务不会全速运行。

【讨论】:

  • 我刚刚检查了总耗时,串行仍然比并行少了 3-4 秒
  • @LelouchLamperouge。如果我调整您的脚本并运行它,我会在并行部分始终更快。因此,我猜这与您正在调用的外部脚本有关。
【解决方案3】:

当您使用多处理时,您应该为工作进程提供足够的计算以至少持续几秒钟。如果工作进程结束得太快,那么会花费太多时间来设置池、生成子进程以及(可能)在进程之间切换(实际上没有足够的时间进行预期的计算)来证明使用multiprocessing 是合理的。

另外,如果您有一个 CPU 密集型计算,那么初始化一个进程数多于内核数的池 (multiprocessing.cpu_count()) 会适得其反。它会使操作系统在进程之间切换,同时不允许计算更快地进行。

【讨论】:

  • 我在一个小样本上运行它。我在真实文件上运行脚本,性能差异显示..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-07-30
  • 1970-01-01
  • 2011-03-23
  • 2013-12-07
  • 2018-07-26
  • 2012-04-23
相关资源
最近更新 更多