9

そのため、Python のグローバル インタープリター ロック(GIL)がどのように機能するかについて、私は一般的にかなりよく理解しています。基本的に、インタープリターの実行中、1 つのスレッドが N ティック (Nを使用して設定できますsys.setcheckinterval) の間 GIL を保持し、その時点で GIL が解放され、別のスレッドが GIL を取得できます。これは、1 つのスレッドが I/O 操作を開始した場合にも発生します。

私が少し混乱しているのは、これがすべて C 拡張モジュールでどのように機能するかということです。

GIL を取得してから を使用して Python コードを実行する C 拡張モジュールがある場合PyEval_EvalCode、インタープリターは GIL を解放して他のスレッドに渡すことができますか? それとも、GIL を取得した C スレッドは、PyEval_EvalCode戻って GIL が C で明示的に解放されるまで、GIL を永続的に保持しますか?

PyGILState gstate = PyGILState_Ensure();

....

/* Can calling PyEval_EvalCode release the GIL and let another thread acquire it?? */
PyObject* obj = PyEval_EvalCode(code, global_dict, local_dict); 

PyGILState_Release(gstate);
4

2 に答える 2

4

はい、インタープリターはいつでも GIL を解放できます。十分な命令を解釈した後、または何らかの I/O を実行する場合は自動的に他のスレッドに渡します。最近の Python 3.x 以降、基準は実行された命令の数ではなく、十分な時間が経過したかどうかに基づくことに注意してください。

別の効果を得るには、明示的に解放するまで GIL を解放しないように要求することにより、GIL を「アトミック」モードで取得する方法が必要です。これは今のところ不可能です (ただし、実験バージョンについてはhttps://bitbucket.org/arigo/cpython-withatomicを参照してください)。

于 2013-04-28T12:03:43.403 に答える
1

アルミンが言ったように、GILは内部で解放できますPyEval_EvalCode. 戻ってきたらもちろん再取得。

最善の方法は、コードがそれを処理できることを確認することです。たとえば、GIL が解放される前に、C ポインタがあるオブジェクトを incref します。また、Python コードがまったく同じ関数を再度呼び出す場合があるので注意してください。そこに別のミューテックスがある場合、簡単にデッドロックに陥る可能性があります。再帰的に安全なミューテックスを使用し、それらを待機している間は、元のスレッドがそのようなミューテックスを解放できるように GIL を解放する必要があります。

于 2013-10-15T15:41:19.197 に答える