0

コード、より具体的には次の(および同様の)スニペットのサイトン化に問題があります。

cdef double [:,:] grad_d_him_d_jm
grad_d_ihm_d_jm = grad_d_im_d_jm(...)

grad_d_im_d_jm(...) は double [:,:] メモリビューを返します。このコードは、Cython によって次の C コードに変換されます。

__pyx_t_1 = __pyx_f_24gradient_better_c_mviews_grad_d_im_d_jm(__pyx_v_i, __pyx_v_j, __pyx_v_m, __pyx_v_structure, __pyx_v_distances); 
if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 203;  __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_t_7 = __Pyx_PyObject_to_MemoryviewSlice_dsds_double(__pyx_t_1);
if (unlikely(!__pyx_t_7.memview)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 203; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_v_grad_d_ihm_d_jm = __pyx_t_7;
__pyx_t_7.memview = NULL;
__pyx_t_7.data = NULL;

これをループで行っているため、Python API 呼び出しがコードの速度にかなりの影響を与えていると思われます。

GOTREF / DECREF 呼び出しは、PyFloat_asFloat とともに、他の機会にも発生します。

cdef float sp
sp = scalar_product()

scalar_product() は cdef float を返します。このスニペットは翻訳されます

__pyx_t_1 = __pyx_f_24gradient_better_c_mviews_scalar_product(__pyx_v_i, __pyx_v_j, __pyx_v_m, __pyx_v_structure); 
if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 178; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_t_2 = __pyx_PyFloat_AsFloat(__pyx_t_1); 
if (unlikely((__pyx_t_2 == (float)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 178; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_v_sp = __pyx_t_2;

Python 2.7.11+ と Cython 0.23.4 を実行しています。a) これはパフォーマンスには関係ないか、b) 修正方法のいずれかを教えていただければ幸いです。質問を改善できるかどうか教えてください。喜んでそうします。

4

1 に答える 1

2

これらは、ここで説明されている Cython 参照カウント API の一部のようです。

私の推測でgrad_d_im_d_jmは、Python オブジェクト (NumPy 配列など) を返すため、Cython はメモリビューが取得された後にオブジェクト参照カウンターをデクリメントする必要があります。

についてscalar_productは、(cdef ではなく) def であるか、型指定されていないと思います。たとえば、次の

cdef g():
    return 1.0

にコンパイルします

// ...
__Pyx_XDECREF(__pyx_r);
__Pyx_INCREF(__pyx_float_1_0);
__pyx_r = __pyx_float_1_0;
goto __pyx_L0;

ただし、戻り値の型を指定すると、refcounting 呼び出しはなくなります

cdef float g():
    return 1.0

になる

// ...
__pyx_r = 1.0;
goto __pyx_L0;
于 2016-05-25T17:55:21.120 に答える