グローバルインタープリターロックとは何ですか?なぜ問題なのですか?
PythonからGILを削除することについて多くのノイズが出されました。なぜそれが重要なのかを理解したいと思います。私はコンパイラーもインタープリターも自分で書いたことがないので、詳細にwith約しないでください。おそらく理解する必要があります。
PythonのGILは、異なるスレッドからインタープリター内部へのアクセスをシリアル化することを目的としています。マルチコアシステムでは、複数のスレッドが複数のコアを効果的に利用できないことを意味します。 (GILがこの問題を引き起こさなかった場合、ほとんどの人はGILを気にしません。マルチコアシステムの普及が進んでいるため、問題として取り上げられているだけです。)詳細を理解したい場合は、 この動画 を表示するか、 このスライドのセット をご覧ください。それは情報が多すぎるかもしれませんが、その後詳細を尋ねました:-)
PythonのGILは、実際にはリファレンス実装であるCPythonの問題にすぎないことに注意してください。 JythonとIronPythonにはGILがありません。 Python開発者として、C拡張を書いているのでない限り、一般にGILに出くわすことはありません。 C拡張機能の作成者は、拡張機能がI/OをブロックするときにGILを解放する必要があるため、Pythonプロセス内の他のスレッドが実行できるようになります。
実際に相互のデータに触れない複数のスレッドがあるとします。これらは可能な限り独立して実行する必要があります。 (たとえば)関数を呼び出すために取得する必要がある「グローバルロック」がある場合、それがボトルネックになる可能性があります。そもそも複数のスレッドを使用しても、あまりメリットは得られません。
実世界の例えに例えると、コーヒーマグが1つしかない会社で100人の開発者が働いているとします。ほとんどの開発者は、コーディングの代わりにコーヒーを待つことに時間を費やすでしょう。
これはいずれもPython固有ではありません。そもそもGILが必要だったPythonの詳細はわかりません。ただし、一般的な概念のより良いアイデアが得られることを願っています。
まず、python GILが提供するものを理解しましょう。
すべての操作/命令はインタープリターで実行されます。 GILは、インタープリターが特定の瞬間で単一のスレッドによって保持されるようにします。そして、複数のスレッドを持つpythonプログラムは、単一のインタープリターで動作します。特定の時点で、このインタープリターは単一のスレッドによって保持されます。これは、インタープリターを保持しているスレッドのみが実行中 at 任意の瞬間であることを意味します。
今、なぜそれが問題なのですか:
マシンに複数のコア/プロセッサが搭載されている可能性があります。また、複数のコアを使用すると、複数のスレッドを実行できます同時つまり、複数のスレッドを実行できます特定の時点で。しかし、インタープリターは単一のスレッドに保持されているため、他のスレッドはコアにアクセスしていても何もしていません。そのため、複数のコアが提供する利点は得られません。現在、インタープリターを保持しているスレッドが使用しているコアである単一のコアのみが使用されているためです。そのため、プログラムは、シングルスレッドプログラムであるかのように実行に時間がかかります。
ただし、I/O、画像処理、NumPyの数値計算など、潜在的にブロックまたは長時間実行される操作は、GILの外部で発生します。 here から取得。そのため、このような操作では、GILが存在していても、マルチスレッド操作はシングルスレッド操作よりも高速です。そのため、GILは必ずしもボトルネックではありません。
編集:GILはCPythonの実装の詳細です。 IronPythonとJythonにはGILがないため、PyPyとJythonを一度も使用したことがないため、本当にマルチスレッド化されたプログラムを使用できます。
Pythonは、Wordの真の意味でのマルチスレッドを許可していません。マルチスレッドパッケージがありますが、コードを高速化するためにマルチスレッドを使用する場合は、通常、使用することはお勧めできません。 Pythonには、Global Interpreter Lock(GIL)と呼ばれる構造があります。
https://www.youtube.com/watch?v=ph374fJqFPE
GILは、一度に1つの「スレッド」のみを実行できるようにします。スレッドはGILを取得し、少し作業を行ってから、GILを次のスレッドに渡します。これは非常に迅速に行われるため、人間の目にはスレッドが並列に実行されているように見えるかもしれませんが、実際には同じCPUコアを使用して交互に実行しています。このすべてのGILの受け渡しは、実行にオーバーヘッドを追加します。これは、コードをより速く実行したい場合、スレッドパッケージを使用することはよくないことを意味します。
Pythonのスレッドパッケージを使用する理由があります。いくつかの処理を同時に実行したい場合で、効率が問題にならない場合は、まったく問題なく便利です。または、何か(IOなど)を待つ必要があるコードを実行している場合、それは非常に理にかなっています。ただし、スレッドライブラリでは余分なCPUコアを使用できません。
マルチスレッド化は、(マルチプロセッシングを行うことにより)オペレーティングシステム、Pythonコード(たとえば、SparkまたはHadoop)を呼び出す外部アプリケーション、またはPythonコードの呼び出し(例:Pythonコードに、高価なマルチスレッド処理を行うC関数を呼び出させることができます)。
2つのスレッドが同じ変数にアクセスするたびに問題が発生します。たとえば、C++では、この問題を回避する方法は、2つのスレッドが、たとえばオブジェクトのセッターを同時に入力することを防ぐために、相互排他ロックを定義することです。
Pythonではマルチスレッドが可能ですが、1つのpython命令よりも細かい粒度で2つのスレッドを同時に実行することはできません。実行中のスレッドはGILと呼ばれるグローバルロックを取得しています。
つまり、マルチコアプロセッサを活用するためにマルチスレッドコードを記述し始めても、パフォーマンスは向上しません。通常の回避策は、マルチプロセスに移行することです。
たとえば、Cで記述したメソッドの内部にいる場合、GILを解放することができることに注意してください。
GILの使用はPythonに固有のものではなく、最も一般的なCPythonを含むそのインタープリターの一部に固有のものです。 (#編集済み、コメントを参照)
GILの問題は、Python 3000でも引き続き有効です。
視覚効果のためのマルチスレッドの本の例を共有したいと思います。だからここに古典的なデッドロックの状況があります
static void MyCallback(const Context &context){
Auto<Lock> lock(GetMyMutexFromContext(context));
...
EvalMyPythonString(str); //A function that takes the GIL
...
}
次に、デッドロックを引き起こすシーケンス内のイベントを検討します。
╔═══╦════════════════════════════════════════╦══════════════════════════════════════╗
║ ║ Main Thread ║ Other Thread ║
╠═══╬════════════════════════════════════════╬══════════════════════════════════════╣
║ 1 ║ Python Command acquires GIL ║ Work started ║
║ 2 ║ Computation requested ║ MyCallback runs and acquires MyMutex ║
║ 3 ║ ║ MyCallback now waits for GIL ║
║ 4 ║ MyCallback runs and waits for MyMutex ║ waiting for GIL ║
╚═══╩════════════════════════════════════════╩══════════════════════════════════════╝
なぜPython(CPythonなど)がGILを使用するのか
から http://wiki.python.org/moin/GlobalInterpreterLock
CPythonでは、グローバルインタープリターロック(GIL)は、複数のネイティブスレッドがPythonバイトコードを同時に実行することを防ぐミューテックスです。このロックは、主にCPythonのメモリ管理がスレッドセーフではないために必要です。
Pythonから削除する方法は?
Luaのように、おそらくPythonは複数のVMを起動できますが、pythonはそれを行いません。他の理由があるはずです。
Numpyまたはその他のpython拡張ライブラリでは、GILを他のスレッドにリリースすると、プログラム全体の効率が向上する場合があります。