12

foo引数としてメモリへのポインタを取り、そのメモリへの書き込みと読み取りの両方を行う関数があります。

cdef void foo (double *data):
   data[some_index_int] = some_value_double
   do_something_dependent_on (data)

私はdata次のように割り当てています:

cdef int N = some_int
cdef double *data = <double*> malloc (N * sizeof (double))

cdef int i
for i in cython.parallel.prange (N, nogil=True):
    foo (data)

readout (data)

私の質問は今です: 異なるスレッドはこれをどのように扱いますか? 私の推測では、 が指すメモリはdataすべてのスレッドで共有され、 function 内で「同時に」読み書きされると思いますfoo。以前に設定されたデータ値(内)に依存できないため、これによりすべての結果が台無しになりますfooか?私の推測は正しいですか、それとも cython-compiler に魔法の安全帯が実装されていますか?

事前にどうもありがとうございました。

4

2 に答える 2

9

良い方法は、メイン配列をスレッドの外に配置することです。次に、スレッドによって計算されるメイン配列の部分へのポインターを各スレッドに渡します。

次の例は、行列乗算 ( dot2 次元配列の場合と同様)の実装です。

c = a*b

ここでの並列処理は の行に対して実装されていますamultiply異なるスレッドが同じ配列を共有できるようにするために、ポインターが関数にどのように渡されるかを確認してください。

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]

確認するには、次のスクリプトを使用できます。

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)

私のコンピューターのどこでそれが得られますか:

finished dot: 0.601547366526 s
finished mydot: 2.834147917 s
Passed test: True

の行数が列の数または の列の数aよりも少ない場合、並列処理を行う次元をより適切にチェックする必要があります。bmydot

于 2013-12-11T13:21:31.970 に答える