PythonがGILで書かれたのはなぜですか?

グローバルインタープリターロック(GIL)は、Pythonでスレッド化などがちょっと難しい理由としてよく引用されているようです-これは疑問を投げかけます「そもそもなぜそれが行われたのですか?」

プログラマーではないので、なぜそうなるのかわかりません。GILを導入する背後にある論理は何でしたか?

コメント

  • ウィキペディアの記事には、 " GILは、並列処理に対する重大な障壁になる可能性があります。これは、言語のダイナミズムを持つために支払われる代償です" 、さらに "このようなロックを使用する理由には、シングルスレッドプログラムの速度の向上(すべてのデータ構造のロックを個別に取得または解放する必要がない)、および通常はCライブラリの簡単な統合が含まれます。スレッドセーフではありません。"
  • @RobertHarvey、ダイナミズムは何の関係もありませんそれと。問題は突然変異です。
  • stackoverflow.com/questions/265687/ …
  • ' Java 'のように符号なしの数値がないことを感じずにはいられません。これは、 '彼らが'自分の足で何をしているのかわからない。残念ながら、知っている人は誰でも'言語が不足していることになります。これは、Pythonが他の多くの方法で揺れるため、非常に残念です。
  • @Basic暗号計算を行うには、Javaでバイト配列を処理するための標準的な方法が必要です('長い間使用していません)。たとえば、Pythonは'署名された番号を持っていませんが、'があるので、ビット単位の操作を実行しようとはしません。より良い方法。

回答

Pythonにはいくつかの実装があります。たとえば、CPython、IronPython、RPython、など。

GILを備えているものと備えていないものがあります。たとえば、CPythonにはGILがあります。

From http://en.wikipedia.org/wiki/Global_Interpreter_Lock

GILを使用してプログラミング言語で記述されたアプリケーションは、各プロセスに独自のインタープリターとがあり、完全な並列処理を実現するために個別のプロセスを使用するように設計できます。次に、独自のGILがあります。

GILの利点

  • シングルスレッドプログラムの速度の向上。
  • 通常はスレッドセーフではないCライブラリの簡単な統合。

Python(CPythonなど)がGILを使用する理由

CPythonでは、グローバルインタープリターロック(GIL)は、複数のネイティブスレッドがPythonバイトコードを一度に実行するのを防ぐミューテックスです。このロックが必要なのは、主にCPythonのメモリ管理がスレッドセーフではないためです。

GILは、マルチスレッドCPythonプログラムが特定の状況でマルチプロセッサシステムを最大限に活用できないため、物議を醸しています。 I / O、画像処理、NumPy番号の処理などの長時間実行される操作は、GILの外部で発生します。したがって、GILがCPythonバイトコードを解釈して、GILの内部で多くの時間を費やすのは、マルチスレッドプログラムでのみです。ボトルネック。

<からp> Pythonには、いくつかの理由から、きめ細かいロックとは対照的にGILがあります。

  • シングルスレッドの場合の方が高速です。

  • i / oバウンドプログラムのマルチスレッドの場合は高速です。

  • cpuバウンドプログラムのマルチスレッドの場合は高速です。 Cライブラリでの計算集約型の作業。

  • C拡張機能の記述が簡単:Pythonスレッドの切り替えは、許可されている場合を除いて行われません(つまり、 Py_BEGIN_ALLOW_THREADSマクロとPy_END_ALLOW_THREADSマクロの間)。

  • Cライブラリのラップが簡単になります。スレッドセーフについて心配する必要はありません。ライブラリがスレッドセーフでない場合は、呼び出す間、GILをロックしたままにしておくだけです。

GILは次のことができます。 Pythonの標準ライブラリは、ブロッキングI / O呼び出しごとにGILをリリースします。したがって、GILはI / Oバウンドサーバーのパフォーマンスに影響を与えません。したがって、プロセス(フォーク)、スレッド、または非同期I / Oを使用してPythonでネットワークサーバーを作成でき、GILが邪魔になりません。

CまたはFortranの数値ライブラリも同様にGILがリリースされました。 C拡張機能がFFTの完了を待機している間、インタープリターは他のPythonスレッドを実行します。したがって、この場合も、GILはきめ細かいロックよりも簡単で高速です。これは数値作業の大部分を構成します。 NumPy拡張機能は可能な限りGILを解放します。

スレッドは通常、ほとんどのサーバープログラムを作成するための悪い方法です。負荷が低い場合、フォークは簡単です。負荷が高い場合は、非同期I / Oとイベント駆動型プログラミング(PythonのTwistedフレームワークを使用するなど)の方が適しています。スレッドを使用する唯一の言い訳は、Windowsにos.forkがないことです。

GILは、純粋なPythonでCPUを集中的に使用する作業を行っている場合にのみ問題になります。ここでは、プロセスとメッセージパッシング(mpi4pyなど)を使用してよりクリーンな設計を行うことができます。Pythonチーズには「処理」モジュールもあります。ショップ、プロセスにスレッドと同じインターフェイスを提供します(つまり、threading.Threadをprocessing.Processに置き換えます)。

スレッドを使用して、GILに関係なくGUIの応答性を維持できます。GILがパフォーマンスを損なう場合(上記の説明を参照)、スレッドにプロセスを生成させ、プロセスが終了するのを待つことができます。

コメント

  • 酸っぱいブドウのように聞こえますPythonは'スレッドを適切に実行できないため、スレッドが不要または不良である理由を説明します。"負荷がかかる場合低い、fo真剣に、rkingは簡単です"?また、GILは、参照カウントGCの使用を主張する場合にのみ、これらすべてのケースで"高速"になります。
  • s/RPython/PyPy/g。 @MichaelBorgwardtプロGILが問題のポイントのようなものである理由を説明します、そうではありませんか?'この回答の内容の一部(つまり、代替案の議論)は要点を超えていることに同意します。そして、良くも悪くも、refcountingを取り除くことは今ではほとんど不可能です-それはAPIとコードベース全体に深く根付いています。 'コードの半分を書き直し、すべての外部コードを壊さずにそれを取り除くことはほとんど不可能です。
  • ドン' multiprocessingライブラリを忘れないでください-2.6以降の標準。 'のワーカープールは、いくつかの単純なタイプの並列処理を非常に巧妙に抽象化したものです。
  • @alcalde実行しない場合のみ' '何をしているのかわからない、および/またはスレッドが協調して動作できるようにしたくない'通信します。それ以外の場合、特に一部のOSで新しいプロセスを起動するオーバーヘッドを考慮すると、'は裏側に大きな苦痛をもたらします。 32コアのサーバーがあるため、CPythonでそれらを完全に利用するには' 32プロセスが必要です。その'は"良い解決策ではありません"それ' CPython 'の不備を回避するためのハック。
  • スレッドがWindows以外のプラットフォームに存在するという事実は、フォークがないことを十分に証明する必要があります。 'すべての状況で適切ではありません。

回答

最初off:PythonにはGILがありません。Pythonはプログラミング言語です。プログラミング言語は抽象的な数学的規則と制限のセットです。Python言語仕様には、GILが必要であると書かれているものはありません。

Pythonにはさまざまな実装があります。GILを備えているものと備えていないものがあります。

GILを使用する簡単な説明の1つは、同時コードの記述が難しいことです。コードの周りにジャイアントロックを配置することで、コードを常にシリアルに実行するように強制します。問題は解決しました!

特にCPythonでは、重要な目標の1つは、Cで記述されたプラグインを使用してインタープリターを簡単に拡張できるようにすることです。繰り返しになりますが、並行コードの記述は難しいため、並行性により、インタプリタの拡張機能を簡単に作成できます。さらに、これらの拡張機能の多くは、同時実行性を考慮して作成されていない可能性のある既存のライブラリの単なる薄いラッパーです。

コメント

  • その'はJava 'の符号なし数値型の欠如と同じ議論です-開発者は他の誰もが彼らよりも愚かだと思っています…
  • @ Basic-信じられないかもしれませんが、'本当に馬鹿ではない場合でも、仮定を単純化する言語を使用していることがわかります。 '特定のことを考えて機能させることは、依然として有用なことです。CPythonは、単純なマルチスレッドアプリケーション(プログラムがIOバウンドであり、多くの場合、GILは重要ではない)を含む特定の用途に最適です。これは、設計上の決定が行われたためです。' GILの最良のソリューションは、これらのアプリケーションのプログラミングを容易にします。特に、コレクションのアトミック操作をサポートしているという事実です。
  • @Julesはい、'これらの機能が必要になるまで、非常に便利です。 cpython ' s "推奨される"ソリューション" c ++ "のような別の言語で書くだけで、Pythonの利点をすべて失うことになります。 'コードの半分をC ++で記述している場合、なぜPythonから始めるのでしょうか。確かに、小さなAPI /接着剤プロジェクトの場合は'すばやく簡単に、ETLの場合は'他に類を見ませんが、'は、重い物を持ち上げる必要があるものには適していません。 Javaを使用してハードウェアと通信するのと同じです… 'ジャンプする必要のあるフープはほとんどコミカルです。
  • @Basic One of Python '、したがってCPython 'のコア哲学は、テクノロジーを"フレンドリーで使いやすい"。グローバルロックなしの並列プログラミングはそうではありません。 GILを使用しない実装が多数あることを考えると、GILを含む実装を少なくとも1つ提供することは理にかなっています。
  • "少なくとも提供することは理にかなっています。それを備えた1つの実装。"そのような'は明らかな結論ですが、他の言語はありません'このように開発者を困惑させていることを認識しているため、'それを明白にすることはできません。

回答

GILの目的は何ですか?

CAPIドキュメントには、この件について次のように記載されています。

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

つまり、GILは状態の破損を防ぎます。メモリセーフな操作のみが許可されているため、Pythonプログラムでセグメンテーション違反が発生することはありません。 GILは、この保証をマルチスレッドプログラムに拡張します。

代替手段は何ですか?

GILの目的が状態を破損から保護することである場合、1つの明白な代替手段は、はるかに細かい粒度でロックすることです。おそらくオブジェクトごとのレベルで。これに伴う問題は、マルチスレッドプログラムのパフォーマンスを向上させることが実証されていますが、オーバーヘッドが大きく、結果としてシングルスレッドプログラムが影響を受けることです。

コメント

  • ユーザーに、きめ細かいロックのgilを置き換えるインタープリターオプションを使用してプログラムを実行させ、現在のプロセスが発生したかどうかを読み取り専用の方法で知ることができれば素晴らしいと思います。 gil。
  • GILにもかかわらず、モジュールpyodbcを不注意に使用したため、マルチスレッドプログラムでセグメンテーション違反が発生しました。したがって、"はセグメンテーション違反を引き起こしてはなりません"は誤りです。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です