web-dev-qa-db-ja.com

なぜグローバル通訳ロックなのか?

Pythonのグローバルインタープリターロックの正確な機能は何ですか?バイトコードにコンパイルされた他の言語も同様のメカニズムを採用していますか?

86

一般に、スレッドセーフの問題では、内部データ構造をロックで保護する必要があります。これは、さまざまなレベルの粒度で実行できます。

  • 個別の構造ごとに独自のロックがある細粒度ロックを使用できます。

  • 1つのロックですべてを保護する粗粒度ロックを使用できます(GILアプローチ)。

各方法にはさまざまな長所と短所があります。きめの細かいロックにより、並列性が向上します。2つのスレッドがリソースを共有しない場合は、並列で実行できます。ただし、はるかに大きな管理オーバーヘッドがあります。コードのすべての行で、いくつかのロックを取得して解放する必要がある場合があります。

大まかなアプローチはその逆です。 2つのスレッドを同時に実行することはできませんが、個々のスレッドはあまり簿記を行わないため、より速く実行されます。最終的には、シングルスレッドの速度と並列処理の間のトレードオフになります。

PythonでGILを削除する試みはいくつかありましたが、シングルスレッドマシンの余分なオーバーヘッドは一般的に大きすぎます。ロックの競合が原因で、マルチプロセッサマシンでも実際には遅くなる場合があります。

バイトコードにコンパイルされた他の言語も同様のメカニズムを採用していますか?

これはさまざまであり、実装プロパティほど言語プロパティと見なすべきではありません。たとえば、Python GILアプローチではなく、基盤となるVMのスレッドアプローチを使用するJythonやIronPythonなどの実装があります。さらに、Ruby動いているように見える に向かって GILを導入する。

69
Brian

以下は 公式のPython/C APIリファレンスマニュアル からの抜粋です。

Pythonインタプリタは完全にスレッドセーフではありません。マルチスレッドPythonプログラムをサポートするために、現在のスレッドが保持する必要のあるグローバルロックがあります。 Python=オブジェクトに安全にアクセスできます。ロックがないと、最も単純な操作でもマルチスレッドプログラムで問題が発生する可能性があります。たとえば、2つのスレッドが同時に同じオブジェクトの参照カウントをインクリメントする場合、参照カウントは、2回ではなく1回だけ増加することになります。

したがって、グローバルインタープリターロックを取得したスレッドのみがPythonオブジェクトを操作するか、Python/C API関数を呼び出すことができます。マルチスレッドをサポートするためにPythonプログラムの場合、インタープリターは定期的にロックを解放して再取得します-デフォルトでは、100バイトコードの命令ごとに(これはsys.setcheckinterval()で変更できます)。 I/Oを要求するスレッドがI/O操作の完了を待機している間、他のスレッドが実行できるように、ファイルの読み取りや書き込みなどの操作。

それは問題をかなり要約していると思います。

33
Eli Bendersky

グローバルインタープリターロックは、参照カウンターがホースから保護される、大きなミューテックスタイプのロックです。純粋なpythonコードを記述している場合、これはすべて舞台裏で行われますが、PythonをCに埋め込む場合は、明示的に取得/解放する必要がある場合があります。ロック。

このメカニズムは、バイトコードにコンパイルされるPythonに関連していません。Javaには必要ありません。実際、 Jython (pythonがjvmにコンパイルされている)には必要ありません。

参照 この質問

19
David Nehme

Pythonは、Perl 5と同様に、スレッドセーフになるようにゼロから設計されていません。スレッドは事後に移植されたため、グローバルインタープリターロックを使用して、インタープリターの腸内の特定の時点で1つのスレッドのみがコードを実行する場所への相互排除を維持します。

個々のPythonスレッドは、ロックをときどき循環させることにより、インタプリタ自体によって協調的にマルチタスク化されます。

Python Cから他のPython=スレッドがアクティブでこのプロトコルに「オプトイン」するときにアクティブである場合、自分でロックを取得する必要があります。安全でないことは背中の後ろで起こりません。

後でマルチスレッドシステムに進化したシングルスレッドの遺産を持つ他のシステムは、多くの場合、この種のメカニズムを備えています。たとえば、Linuxカーネルには、初期のSMP時代からの「ビッグカーネルロック」があります。時間の経過とともに、マルチスレッドのパフォーマンスが問題になるにつれて、これらの種類のロックをより小さな部分に分割するか、可能な場合は、それらをロックフリーのアルゴリズムとデータ構造に置き換えて、スループットを最大化しようとする傾向があります。

11
Edward KMETT

2番目の質問に関しては、すべてのスクリプト言語がこれを使用しているわけではありませんが、それはそれらの能力を弱めるだけです。たとえば、Rubyのスレッドは green であり、ネイティブではありません。

Pythonでは、スレッドはネイティブであり、GILはそれらが異なるコアで実行されるのを防ぎます。

Perlでは、スレッドはさらに悪化します。それらはインタプリタ全体をコピーするだけで、Pythonのように使用可能になるにはほど遠いです。

7
Eli Bendersky

多分 this BDFLの記事が役立つでしょう。

2
Jeremy Cantrell