【问题标题】:Unexpected behaviour when multiprocessing with numpy arrays of different data types使用不同数据类型的 numpy 数组进行多处理时的意外行为
【发布时间】:2017-09-13 14:32:32
【问题描述】:

在使用不同数据类型的 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。

我已经在array_multiplication 中的for 循环中尝试了许多数组大小大小和迭代次数,并且行为是相同的。我正在运行具有 62.8 GB 内存和 i7-6800k 3.40GHz CPU 的 Ubuntu 16.04 LTS。

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

【问题讨论】:

  • 澄清一下:您的问题不仅仅是问为什么浮点计算比整数计算需要更多的计算量吗?
  • @koalo 是的。我的问题是:为什么多处理比float64 的系列计算花费更多时间,但更重要的是,为什么只指定 4 个时使用所有处理器?

标签: python arrays numpy multiprocessing


【解决方案1】:

这是预期的行为。

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

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

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

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

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

相关question

【讨论】:

  • 这很有趣。您是否会说,实际上,正在进行“复合”多处理,例如,Pool 将任务分配给 4 个处理器,这些处理器又将np.dot() 任务分配给n 更多处理器,创建@987654329 @ 进程(或类似的东西)?当我在Pool 中指定 2 个进程时,实际上有一个加速,而 1 的结果与系列计算的时间相同,而 3 或更多则更慢。
  • 这可能取决于您的操作系统的调度程序,但这就是我所期望的。但是必须注意细节,例如处理器,核心,线程。我也不认为您的示例是一个好示例(其中 2 个进程可能是一件好事),可能是由于外部副本和循环。在大多数情况下,对于这样的操作,经典矢量化会更快(完全跳过 MT)。您也可以在不使用任何其他代码的情况下尝试一些矩阵乘法(大的)来观察您的实现中使用的线程数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多