使用不同数据类型的numpy数组进行多处理时出现意外行为

时间:2017-09-13 14:32:33

标签: python arrays numpy multiprocessing

当使用不同数据类型的numpy数组进行多处理时,我遇到了意外错误。首先,我使用类型为int64的numpy数组执行多处理,然后使用类型为float64的numpy数组再次运行它。 int64按预期运行,而float64使用所有可用处理器(超过我分配的),导致计算速度比使用单核更慢。

以下示例重现了该问题:

def array_multiplication(arr):

    new_arr = arr.copy()

    for nnn in range(3):

        new_arr = np.dot(new_arr, arr)

    return new_arr

if __name__ == '__main__':

    from multiprocessing import Pool
    import numpy as np
    from timeit import timeit

    # Example integer arrays.
    test_arr_1 = np.random.randint(100, size=(100, 100))
    test_arr_2 = np.random.randint(100, size=(100, 100))
    test_arr_3 = np.random.randint(100, size=(100, 100))
    test_arr_4 = np.random.randint(100, size=(100, 100))

    # Parameter array.
    parameter_arr = [test_arr_1, test_arr_2, test_arr_3, test_arr_4]

    pool = Pool(processes=len(parameter_arr))

    print('Multiprocessing time:')
    print(timeit(lambda: pool.map(array_multiplication, parameter_arr), 
          number=1000))

    print('Series time:')
    print(timeit(lambda: list(map(array_multiplication, parameter_arr)), 
          number=1000))

将产生

Multiprocessing speed:
4.1271785919998365
Series speed:
8.102764352000122

这是预期的加速。

但是,用

替换test_arr_n
test_arr_1 = np.random.normal(50, 30, size=(100, 100))
test_arr_2 = np.random.normal(50, 30, size=(100, 100))
test_arr_3 = np.random.normal(50, 30, size=(100, 100))
test_arr_4 = np.random.normal(50, 30, size=(100, 100))

结果

Multiprocessing time:
2.379720258999896
Series time:
0.40820308100001057

除了耗尽所有可用的处理器之外,我已经指定了4.下面是运行第一种情况(int64)和第二种情况(float64)时处理器使用情况的屏幕抓取。

以上是int64案例,其中四个处理器被赋予任务,然后是一个处理器串行计算任务。

但是,在float64情况下,正在使用所有处理器,即使指定的数字是test_arr的数量 - 即4。

我在for的{​​{1}}循环中尝试了多个数组大小和迭代次数,但行为是相同的。我正在运行Ubuntu 16.04 LTS,内存为62.8 GB,i7-6800k为3.40GHz CPU。

为什么会这样?提前致谢。

1 个答案:

答案 0 :(得分:2)

这是预期的行为。

Numpy在内部使用BLAS(对于某些函数),这是高度优化的(Cache,SIMD,并且取决于您使用的实现:多线程;一些实现 - 候选Atlas,OpenBLAS,MKL)并且只是放慢速度使用一些外部多处理(它具有基于IO的开销,也可能会损害缓存行为)!

现代Ubuntu版本默认带有多线程BLAS实现(之前的版本仅限于1或2个线程)。

numpy中基于BLAS的函数的经典示例是np.dot()

大多数BLAS实现(我都知道;看到一些讨论@Intel用于向MKL添加对离散类型的一些有限支持)only support floating-point types,所以这就是为什么这两个代码表现不同的原因(一个高度优化,另一个不是;一个受多处理伤害,另一个没有)。

从技术上讲,我不会称之为错误,但这是你所描述的观察结果!

相关question