当使用不同数据类型的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。
为什么会这样?提前致谢。
答案 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。