良い方法は、メイン配列をスレッドの外側に配置することです。次に、スレッドによって計算されるべきメイン配列の部分へのポインタを各スレッドに渡します。ここで
c = a*b
平行度がa
の行の上に実装されている:
次の例では、(2-Dアレイのdot
に類似)行列乗算の実装です。異なるスレッドが同じ配列を共有できるように、ポインタがmultiply
関数にどのように渡されるかを確認してください。 a
の行数がCOLSのその後数よりも小さかった場合
finished dot: 0.601547366526 s
finished mydot: 2.834147917 s
Passed test: True
:
import time
import numpy as np
import _stack
a = np.random.random((10000,500))
b = np.random.random((500,2000))
t = time.clock()
c = np.dot(a, b)
print('finished dot: {} s'.format(time.clock()-t))
t = time.clock()
c2 = _stack.mydot(a, b)
print('finished mydot: {} s'.format(time.clock()-t))
print 'Passed test:', np.allclose(c, c2)
私のコンピュータ上でそれが与える:
import numpy as np
cimport numpy as np
import cython
from cython.parallel import prange
ctypedef np.double_t cDOUBLE
DOUBLE = np.float64
def mydot(np.ndarray[cDOUBLE, ndim=2] a, np.ndarray[cDOUBLE, ndim=2] b):
cdef np.ndarray[cDOUBLE, ndim=2] c
cdef int i, M, N, K
c = np.zeros((a.shape[0], b.shape[1]), dtype=DOUBLE)
M = a.shape[0]
N = a.shape[1]
K = b.shape[1]
for i in prange(M, nogil=True):
multiply(&a[i,0], &b[0,0], &c[i,0], N, K)
return c
@cython.wraparound(False)
@cython.boundscheck(False)
@cython.nonecheck(False)
cdef void multiply(double *a, double *b, double *c, int N, int K) nogil:
cdef int j, k
for j in range(N):
for k in range(K):
c[k] += a[j]*b[k+j*K]
は、このスクリプトを使用することができます確認するにはまたはb
mydot
の列の数が悪くなり、どの次元を並列化するかをよりよく確認する必要があります。
** NB:**私は自分のシステムでOpenMPを持っていないので、これを簡単にテストすることはできません。 –