numba guvectorize target='parallel'比target='cpu'慢'

2024-09-28 22:29:38 发布

您现在位置:Python中文网/ 问答频道 /正文

我一直在尝试优化一段涉及大型多维数组计算的python代码。我对numba有违反直觉的结果。我运行的是MBP,2015年年中,2.5GHz i7 quadcore,OS 10.10.5,Python2.7.11。考虑以下因素:

 import numpy as np
 from numba import jit, vectorize, guvectorize
 import numexpr as ne
 import timeit

 def add_two_2ds_naive(A,B,res):
     for i in range(A.shape[0]):
         for j in range(B.shape[1]):
             res[i,j] = A[i,j]+B[i,j]

 @jit
 def add_two_2ds_jit(A,B,res):
     for i in range(A.shape[0]):
         for j in range(B.shape[1]):
             res[i,j] = A[i,j]+B[i,j]

 @guvectorize(['float64[:,:],float64[:,:],float64[:,:]'],
    '(n,m),(n,m)->(n,m)',target='cpu')
 def add_two_2ds_cpu(A,B,res):
     for i in range(A.shape[0]):
         for j in range(B.shape[1]):
             res[i,j] = A[i,j]+B[i,j]

 @guvectorize(['(float64[:,:],float64[:,:],float64[:,:])'],
    '(n,m),(n,m)->(n,m)',target='parallel')
 def add_two_2ds_parallel(A,B,res):
     for i in range(A.shape[0]):
         for j in range(B.shape[1]):
             res[i,j] = A[i,j]+B[i,j]

 def add_two_2ds_numexpr(A,B,res):
     res = ne.evaluate('A+B')

 if __name__=="__main__":
     np.random.seed(69)
     A = np.random.rand(10000,100)
     B = np.random.rand(10000,100)
     res = np.zeros((10000,100))

我现在可以在各种函数上运行timeit:

^{pr2}$

似乎“parallel”甚至不需要使用单个核心的大部分,因为它在top中的使用表明python的“parallel”占用了~40%的cpu,“cpu”占用了~100%,numexpr达到了~300%。在


Tags: inimportaddforparalleldefnprange
1条回答
网友
1楼 · 发布于 2024-09-28 22:29:38

@guvectorize实现有两个问题。第一种情况是,您正在@guvectorize内核中执行所有循环,因此Numba parallel目标实际上没有什么可以并行化的。在ufunc/gufunc中,@vectorize和@guvectorize在广播维度上都是并行的。由于gufunc的签名是2D的,而您的输入是2D的,因此只有一个对内部函数的调用,这解释了您看到的CPU使用率只有100%。在

编写上述函数的最佳方法是使用常规ufunc:

@vectorize('(float64, float64)', target='parallel')
def add_ufunc(a, b):
    return a + b

然后在我的系统中,我看到这些速度:

^{pr2}$

(这是一个非常类似于您的OS X系统,但使用的是OS X 10.11。)

尽管Numba的parallel ufunc现在已经超过了numexpr(我看到add_ufunc使用了大约280%的CPU),但它并没有打败简单的单线程CPU情况。我怀疑瓶颈是由于内存(或缓存)带宽造成的,但我还没有进行测量来检查这一点。在

一般来说,如果对每个内存元素执行更多的数学运算(比如余弦),那么并行ufunc目标会带来更多的好处。在

相关问题 更多 >