メモリ ビューが便利で高速であることがわかったので、cython で NumPy 配列を作成することを避け、指定された配列のビューを操作するようにしています。ただし、既存の配列を変更するのではなく、新しい配列を作成することが避けられない場合があります。上位の関数ではこれは目立ちませんが、頻繁に呼び出されるサブルーチンでは目立ちます。次の関数を検討してください
#@cython.profile(False)
@cython.boundscheck(False)
@cython.wraparound(False)
@cython.nonecheck(False)
cdef double [:] vec_eq(double [:] v1, int [:] v2, int cond):
''' Function output corresponds to v1[v2 == cond]'''
cdef unsigned int n = v1.shape[0]
cdef unsigned int n_ = 0
# Size of array to create
cdef size_t i
for i in range(n):
if v2[i] == cond:
n_ += 1
# Create array for selection
cdef double [:] s = np.empty(n_, dtype=np_float) # Slow line
# Copy selection to new array
n_ = 0
for i in range(n):
if v2[i] == cond:
s[n_] = v1[i]
n_ += 1
return s
プロファイリングは、ここで得られる速度があることを教えてくれます。私
ができることは、関数を適応させることです。たとえば、このベクトルの平均が計算されたり、合計が計算されたりすることがあります。だから、合計したり平均を取ったりするために、それを書き直すことができました。しかし、サイズを動的に定義して、オーバーヘッドがほとんどないメモリビューを直接作成する方法はありませんか。最初に etc を使用してac バッファーを作成し、関数の最後でバッファーをビューに変換し、ポインターとストライドなどを渡すようなもの..
malloc
編集1: 単純なケースの場合、たとえばこのように関数を適応させることは、受け入れられるアプローチです。引数と合計/平均を取るだけを追加しました。この方法では、配列を作成する必要がなく、関数 malloc 内で簡単に処理できます。これ以上は速くなりませんよね?
# ...
cdef double vec_eq(double [:] v1, int [:] v2, int cond, opt=0):
# additional option argument
''' Function output corresponds to v1[v2 == cond].sum() / .mean()'''
cdef unsigned int n = v1.shape[0]
cdef int n_ = 0
# Size of array to create
cdef Py_ssize_t i
for i in prange(n, nogil=True):
if v2[i] == cond:
n_ += 1
# Create array for selection
cdef double s = 0
cdef double * v3 = <double *> malloc(sizeof(double) * n_)
if v3 == NULL:
abort()
# Copy selection to new array
n_ = 0
for i in range(n):
if v2[i] == cond:
v3[n_] = v1[i]
n_ += 1
# Do further computation here, according to option
# Option 0 for the sum
if opt == 0:
for i in prange(n_, nogil=True):
s += v3[i]
free(v3)
return s
# Option 1 for the mean
else:
for i in prange(n_, nogil=True):
s += v3[i]
free(v3)
return s / n_
# Since in the end there is always only a single double value,
# the memory can be freed right here