2017-10-11 1 views
2

配列を読み込んで配列を返すCython関数を作成したいと思います。この関数は、Pythonのdef関数ではなく、他のcdef関数の中から呼び出されます。ここに私が持っているものがあります。私.pyxファイルでCython:配列を返すC関数を作成する

cdef int[:] array_test(double *x) nogil 

:私の.pxdファイルで

cdef inline int[:] array_test(double *x) nogil: 

    cdef int output[2] 
    output[0]=1 
    output[1]=9 

    return output 

しかし、私は、コンパイル時に、私はエラーを取得: "操作ギルなしで許可されていません" ことができる人助けてください?

答えて

3

おそらく誤解があります。この関数はc配列を返しませんが、メモリビュースライスを返します。あなたは私を信じる必要はありません。nogilを削除してcythonを呼び出して確認できます。作成したの* .cファイルでは、__Pyx_memviewsliceが重要な一部である、あなたの関数のC-署名を確認することができます。

static CYTHON_INLINE __Pyx_memviewslice __pyx_f_4file_array_test(CYTHON_UNUSED double *__pyx_v_x) 

このメモリビューは、Pythonのオブジェクトなので、それはガベージコレクタに登録する必要があり、したがって、グローバルインタープリタロックが必要です。つまり、「Gilなしで操作できません」というエラーメッセージが表示されます。

ですから、少なくとも3つのオプションがあります。

  1. は、「nogil」でそれを行うことは本当にそれほど重要なのですか?もしそうでなければ、それをドロップしてください。最も簡単な解決策、欠点です。パフォーマンスが低下する可能性があります。
  2. 実際のC配列、つまりint *res = (int *) malloc(2*sizeof(int))を使用します。高速ですが、欠点です。自分でメモリを管理する必要があります。
  3. C++とstd::vector<int>を使用すると、メモリを管理する必要はありませんが、C++に切り替える必要があるという利点があります。

可能性1.の改善が(これは実際のコードは、この例かもしれませんがための大きな違いをすることはありません)だけでそれが必要とされる最後の行、ためにギルをAQUIREすることです:

cdef inline int[:] array_test(double *x) nogil: 
    cdef int output[2] 
    output[0]=1 
    output[1]=9 
    with gil: 
     return output 

OPが提案されているように、更なる可能性はに機能の署名を変更することであろう。

ここのトリック:fuction array_testは結果としてメモリビュースライスを作成せず、ガベージコレクタに登録する必要もなく、 "nogil"が可能です。

array_testの呼び出しがより煩雑になり、呼び出し側がoutputメモリビューを作成するためにgilを持たなければならないというようなマイナーなマイナス面があります。しかし、呼び出し側は結果を格納するデータ構造の種類(numpy配列か多分何か)を判断できるという利点もあります。

+0

ありがとうございました!問題を回避する別の方法は、関数を無効にして、空の入力配列を変更することです。 – user3433489

+0

@ user3433489どのように単純です!これについて考えなかった... – ead

関連する問題