我试图对许多独立数据集进行蒙特卡洛模拟的并行化处理。我发现numba的并行guvectorize实现仅比numba jit实现快30-40%。
我在Stackoverflow上找到了这些(1,2)相关主题,但它们并没有真正回答我的问题。在第一个案例中,实现被降级为对象模式而变慢,在第二个案例中,原始发布者未正确使用guvectorize - 这些问题都不适用于我的代码。
为了确保我的代码没有问题,我创建了这个非常简单的代码片段来比较jit和guvectorize:
import timeit
import numpy as np
from numba import jit, guvectorize
#both functions take an (m x n) array as input, compute the row sum, and return the row sums in a (m x 1) array
@guvectorize(["void(float64[:], float64[:])"], "(n) -> ()", target="parallel", nopython=True)
def row_sum_gu(input, output) :
output[0] = np.sum(input)
@jit(nopython=True)
def row_sum_jit(input_array, output_array) :
m, n = input_array.shape
for i in range(m) :
output_array[i] = np.sum(input_array[i,:])
rows = int(64) #broadcasting (= supposed parallellization) dimension for guvectorize
columns = int(1e6)
input_array = np.ones((rows, columns))
output_array = np.zeros((rows))
output_array2 = np.zeros((rows))
#the first run includes the compile time
row_sum_jit(input_array, output_array)
row_sum_gu(input_array, output_array2)
#run each function 100 times and record the time
print("jit time:", timeit.timeit("row_sum_jit(input_array, output_array)", "from __main__ import row_sum_jit, input_array, output_array", number=100))
print("guvectorize time:", timeit.timeit("row_sum_gu(input_array, output_array2)", "from __main__ import row_sum_gu, input_array, output_array2", number=100))
这给我以下输出(时间有些变化):jit time: 12.04114792868495
guvectorize time: 5.415564753115177
因此,尽管并行代码利用了所有CPU核心,而jit代码仅使用一个(使用htop验证),但并行代码的性能优势仅为原来的两倍(仅当行数是CPU核心数的整数倍时才会出现,否则性能优势会降低)。我在一台拥有4个AMD Opteron 6380 CPU(总共64个核心),256GB RAM和Red Hat 4.4.7-1操作系统的机器上运行此代码。我使用Anaconda 4.2.0、Python 3.5.2和Numba 0.26.0。
如何进一步提高并行性能或者我做错了什么?
感谢您的回答。
input_array = np.random.rand(rows, columns)
,并且np.array_equal(output_array, output_array2)
返回 True。 - Dries Van Laethem