Python の Global Interpreter Lock の正確な機能は何ですか? バイトコードにコンパイルされる他の言語は、同様のメカニズムを採用していますか?
6 に答える
一般に、スレッド セーフの問題については、内部データ構造をロックで保護する必要があります。これは、さまざまな粒度レベルで実行できます。
個々の構造ごとに独自のロックを持つ、きめの細かいロックを使用できます。
1 つのロックですべてを保護する粗粒度ロックを使用できます (GIL アプローチ)。
各方法にはさまざまな長所と短所があります。ファイングレイン ロックにより、より優れた並列処理が可能になります。2 つのスレッドがリソースを共有していない場合、2 つのスレッドを並行して実行できます。ただし、はるかに大きな管理オーバーヘッドがあります。コードの行ごとに、いくつかのロックを取得して解放する必要がある場合があります。
粗粒度アプローチはその逆です。2 つのスレッドを同時に実行することはできませんが、個々のスレッドはあまり簿記を行わないため、より高速に実行されます。最終的には、シングルスレッドの速度と並列処理の間のトレードオフになります。
Python で GIL を削除する試みがいくつかありましたが、シングル スレッド マシンの余分なオーバーヘッドは一般的に大きすぎました。場合によっては、ロックの競合が原因で、マルチプロセッサ マシンでも実際には遅くなることがあります。
バイトコードにコンパイルされる他の言語は、同様のメカニズムを採用していますか?
それはさまざまであり、おそらく実装プロパティほど言語プロパティと見なされるべきではありません。たとえば、GIL アプローチではなく、基盤となる VM のスレッド化アプローチを使用する Jython や IronPython などの Python 実装があります。さらに、Ruby の次のバージョンはGIL の導入に向けて動いているようです。
以下は、公式の Python/C API リファレンス マニュアルからのものです。
Python インタープリターは完全にスレッドセーフではありません。マルチスレッドの Python プログラムをサポートするために、現在のスレッドが Python オブジェクトに安全にアクセスできるようにするには、グローバル ロックを保持する必要があります。ロックがないと、最も単純な操作でもマルチスレッド プログラムで問題が発生する可能性があります。たとえば、2 つのスレッドが同じオブジェクトの参照カウントを同時にインクリメントすると、参照カウントが 2 回ではなく 1 回だけインクリメントされる可能性があります。
したがって、グローバル インタープリター ロックを取得したスレッドのみが Python オブジェクトを操作したり、Python/C API 関数を呼び出したりできるという規則が存在します。マルチスレッドの Python プログラムをサポートするために、インタプリタは定期的にロックを解放して再取得します。デフォルトでは、100 バイトコード命令ごとです (これは sys.setcheckinterval() で変更できます)。I/O を要求するスレッドが I/O 操作の完了を待っている間、他のスレッドを実行できるように、ファイルの読み取りや書き込みなどの I/O 操作をブロックする可能性がある場合は、ロックも解放されて再取得されます。
問題をうまくまとめていると思います。
Python は、perl 5 と同様に、最初からスレッド セーフになるように設計されていません。スレッドは事後に移植されたため、グローバル インタープリター ロックを使用して、インタープリターの内部で特定の時間に 1 つのスレッドのみがコードを実行する相互排除を維持します。
個々の Python スレッドは、頻繁にロックを循環させることにより、インタプリタ自体によって協調的にマルチタスク処理されます。
他の Python スレッドがこのプロトコルに「オプトイン」するためにアクティブなときに C から Python と通信している場合は、自分でロックを取得する必要があります。
後にマルチスレッド システムに進化したシングル スレッドの遺産を持つ他のシステムには、多くの場合、この種のメカニズムがあります。たとえば、Linux カーネルには、初期の SMP 時代からの「ビッグ カーネル ロック」があります。マルチスレッドのパフォーマンスが問題になるにつれて、時間の経過とともに徐々に、この種のロックをより小さな断片に分割しようとする傾向があり、スループットを最大化するために可能な場合はロックのないアルゴリズムとデータ構造に置き換えようとする傾向があります。
2 番目の質問については、すべてのスクリプト言語がこれを使用しているわけではありませんが、強力でなくなるだけです。たとえば、Ruby のスレッドはグリーンであり、ネイティブではありません。
Python では、スレッドはネイティブであり、GIL はそれらが異なるコアで実行されるのを防ぐだけです。
Perl では、スレッドはさらに悪化します。それらはインタプリタ全体をコピーするだけであり、Python ほど使いやすくはありません。
BDFLによるこの記事が役立つかもしれません。