辞書を持っています
my_dict = {'a':[1,2,3], 'b':[4,5] , 'c':[7,1,2])
Cython nogil関数内でこの辞書を使用したいと思います。だから、私はそれを次のように宣言しようとしました
cdef dict cy_dict = my_dict
この段階までは結構です。
次に、my_dictのキーを反復処理する必要があります。値がリストにある場合は、それを反復処理します。 Pythonで、次のように非常に簡単です:
for key in my_dict:
if isinstance(my_dict[key], (list, Tuple)):
###### Iterate over the value of the list or Tuple
for value in list:
## Do some over operation.
しかし、Cythonの内部では、nogilの内部にも同じことを実装したいと思います。 pythonオブジェクトはnogil内では許可されていないので、私はすべてここで立ち往生しています。
with nogil:
#### same implementation of the same in Cython
誰か私を助けてくれますか?
本当に賢明な唯一のオプションは、残念ながらGILが必要であることを受け入れることです。 C++マップを含むあまり賢明でないオプションもありますが、特定のケースに適用するのは難しい場合があります。
with gil:
を使用してGILを再取得できます。ここには明らかなオーバーヘッドがあります(GILを使用するパーツは並行して実行できず、GILを待機する遅延がある可能性があります)。ただし、辞書操作がCythonコードの大きな部分の小さなチャンクである場合、これはそれほど悪くないかもしれません。
with nogil:
# some large chunk of computationally intensive code goes here
with gil:
# your dictionary code
# more computationally intensive stuff here
他のあまり賢明でないオプションは、C++マップを使用することです(他のC++標準ライブラリデータ型と一緒に)。 Cythonはこれらをラップして自動的に変換できます。サンプルデータに基づいて簡単な例を示すには:
from libcpp.map cimport map
from libcpp.string cimport string
from libcpp.vector cimport vector
from cython.operator cimport dereference, preincrement
def f():
my_dict = {'a':[1,2,3], 'b':[4,5] , 'c':[7,1,2]}
# the following conversion has an computational cost to it
# and must be done with the GIL. Depending on your design
# you might be able to ensure it's only done once so that the
# cost doesn't matter much
cdef map[string,vector[int]] m = my_dict
# cdef statements can't go inside no gil, but much of the work can
cdef map[string,vector[int]].iterator end = m.end()
cdef map[string,vector[int]].iterator it = m.begin()
cdef int total_length = 0
with nogil: # all this stuff can now go inside nogil
while it != end:
total_length += dereference(it).second.size()
preincrement(it)
print total_length
(これをlanguage='c++'
でコンパイルする必要があります)。
これの明らかな欠点は、dict内のデータ型が事前にわかっている必要があることです(任意のPythonオブジェクトにすることはできません)。ただし、任意の=を操作できないため、 Pythonとにかくかなり制限されているnogil
ブロック内のオブジェクト。