Python多处理Pool.map正在调用aquire?

时间:2010-09-22 17:19:08

标签: python profiling multiprocessing

我有一个640x480图像的numpy.array,每张图像长630张。 因此总阵列为630x480x640。 我想生成一个平均图像,以及计算标准偏差 所有630张图片中的每个像素。

这很容易通过

完成
avg_image = numpy.mean(img_array, axis=0)
std_image = numpy.std(img_array, axis=0)

但是,因为我运行了50个左右这样的数组,并且有一个 8核/ 16线程工作站,我想我会变得贪婪和并行化 multiprocessing.Pool。

所以我做了以下事情:

def chunk_avg_map(chunk):
    #do the processing
    sig_avg = numpy.mean(chunk, axis=0)
    sig_std = numpy.std(chunk, axis=0)
    return([sig_avg, sig_std])

def chunk_avg(img_data):

    #take each row of the image
    chunks = [img_data[:,i,:] for i in range(len(img_data[0]))]

    pool = multiprocessing.Pool()
    result = pool.map(chunk_avg_map, chunks)
    pool.close()
    pool.join()
    return result

然而,我只看到了一个小的加速。通过在chunk_avg_map中放置print语句,我能够确定一次只启动一个或两个进程,而不是 16(正如我所料)。

然后我通过iPython中的cProfile运行我的代码:

%prun current_image_anal.main()

结果表明,到目前为止,大部分时间都用于获取电话:

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     1527  309.755    0.203  309.755    0.203 {built-in method acquire}

我理解与锁定有关,但我不明白为什么我的代码会这样做。有没有人有任何想法?

[编辑]根据要求,这是一个可运行的脚本,演示了这个问题。 您可以通过任何您喜欢的方式对其进行分析,但是当我这样做时,我发现了狮子 分享的时间用于收购,而不是按照我的意愿收费 已经预料到了。

#!/usr/bin/python
import numpy
import multiprocessing

def main():
    fake_images = numpy.random.randint(0,2**14,(630,480,640))
    chunk_avg(fake_images)

def chunk_avg_map(chunk):
    #do the processing
    sig_avg = numpy.mean(chunk, axis=0)
    sig_std = numpy.std(chunk, axis=0)
    return([sig_avg, sig_std])

def chunk_avg(img_data):

    #take each row of the image
    chunks = [img_data[:,i,:] for i in range(len(img_data[0]))]

    pool = multiprocessing.Pool()
    result = pool.map(chunk_avg_map, chunks)
    pool.close()
    pool.join()
    return result

if __name__ == "__main__":
    main()

1 个答案:

答案 0 :(得分:7)

我认为问题在于,处理每个块所需的CPU时间相对于复制输入和输出与工作进程之间所需的时间相比较小。我修改了您的示例代码,将输出拆分为16个偶数块,并打印出time.clock()运行开始和结束之间的CPU时间差异(chunk_avg_map())。在我的系统上,每个单独运行的CPU时间略短于一秒,但进程组的总CPU时间使用(系统+用户时间)超过38秒。每个块的明显0.75秒复制开销使得程序执行计算的速度仅比multiprocessing提供数据的速度略快,导致一次只能使用两个工作进程。

如果我修改代码使得“输入数据”只是xrange(16)并在chunk_avg_map()内构建随机数组,那么我看到sysem +用户时间下降到大约19秒并且所有16个工作者进程同时执行。