基于numpy的计算的低效多处理

fja*_*rri 6 python numpy multiprocessing

我正在尝试并行化一些numpy在Python multiprocessing模块的帮助下使用的计算.考虑这个简化的例子:

import time
import numpy

from multiprocessing import Pool

def test_func(i):

    a = numpy.random.normal(size=1000000)
    b = numpy.random.normal(size=1000000)

    for i in range(2000):
        a = a + b
        b = a - b
        a = a - b

    return 1

t1 = time.time()
test_func(0)
single_time = time.time() - t1
print("Single time:", single_time)

n_par = 4
pool = Pool()

t1 = time.time()
results_async = [
    pool.apply_async(test_func, [i])
    for i in range(n_par)]
results = [r.get() for r in results_async]
multicore_time = time.time() - t1

print("Multicore time:", multicore_time)
print("Efficiency:", single_time / multicore_time)
Run Code Online (Sandbox Code Playgroud)

当我执行它时,multicore_time它大致相等single_time * n_par,而我希望它接近single_time.事实上,如果我numpy用公正的计算取代计算time.sleep(10),这就是我得到的 - 完美的效率.但由于某种原因,它不起作用numpy.这可以解决,还是内部限制numpy

一些可能有用的其他信息:

  • 我正在使用OSX 10.9.5,Python 3.4.2和CPU是Core i7(由系统信息报告)4个内核(虽然上面的程序总共需要50%的CPU时间,所以系统信息可能不要考虑超线程).

  • 当我运行它时,我看到在100%CPU下工作的n_par进程top

  • 如果我用numpy循环和每索引操作替换数组操作,效率会显着提高(约为75%n_par = 4).

Bi *_*ico 8

看起来你正在使用的测试函数是内存限制的.这意味着您所看到的运行时间受到计算机将阵列从内存拉入缓存的速度的限制.例如,该行a = a + b实际上使用了3个数组a,b以及将要替换的新数组a.这三个数组各约为8MB(1e6浮点数*每个浮点数8个字节).我相信不同的i7有3MB - 8MB的共享L3缓存,所以你不能同时在缓存中容纳所有3个阵列.你的cpu添加浮点数比可以加载到缓存中的数组更快,所以大部分时间都花在等待数组从内存中读取.由于缓存是在核心之间共享的,因此您不会通过将工作分散到多个核心来看到任何加速.

内存绑定操作一般都是numpy的问题,我知道处理它们的唯一方法是使用cython或numba之类的东西.