为什么multiprocessing.Pool.map比builtin map慢?

时间:2012-02-07 00:41:14

标签: python multiprocessing performance-testing

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

如何解释这种性能差异?

3 个答案:

答案 0 :(得分:4)

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

此外,如果您有一个CPU绑定计算,那么使用比核心(multiprocessing.cpu_count())更多的进程初始化池会适得其反。它将使OS在进程之间切换,同时不允许计算更快地进行。

答案 1 :(得分:2)

如果“外部脚本”中涉及的工作负载足够IO,使其硬盘饱和,则并行运行多个副本只会减慢速度,因为从多个文件读取会产生额外的搜索。

如果您使CPU饱和并且没有多个CPU核心可用,也是如此。

答案 2 :(得分:1)

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)

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

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