Pythonはマルチスレッドをサポートしていますか?実行時間を短縮できますか?


95

Pythonでマルチスレッドが機能するかどうかについて少し混乱しています。

私はこれについて多くの質問があり、それらの多くを読んだことを知っていますが、私はまだ混乱しています。私は自分の経験から知っており、他の人が自分の答えと例をここでStackOverflowに投稿して、マルチスレッドが実際にPythonで可能であることを確認しました。では、なぜPythonはGILによってロックされており、一度に1つのスレッドしか実行できないと誰もが言い続けるのはなぜでしょうか。それは明らかに機能します。または私がここに来ていないいくつかの違いはありますか?

多くのポスター/回答者は、複数のコアを使用しないため、スレッド化が制限されていることについても言及し続けます。しかし、それらは同時に機能するため、組み合わせたワークロードをより高速に実行できるため、依然として有用です。それ以外の理由でPythonスレッドモジュールが存在するのはなぜですか?

更新:

これまでのすべての答えをありがとう。私が理解している方法では、マルチスレッドは一部のIOタスクに対してのみ並列実行されますが、CPUにバインドされた複数のコアタスクに対しては一度に1つしか実行できません。

これが実際に何を意味するのかは完全にはわかりませんので、マルチスレッドにしたい種類のタスクの例を示します。たとえば、文字列の非常に長いリストをループして、各リストアイテムに対して基本的な文字列操作を実行したいとします。リストを分割し、各サブリストをループ/文字列コードで処理するために新しいスレッドで送信し、結果をキューに送信すると、これらのワークロードはほぼ同時に実行されますか?最も重要なことは、これは理論的にスクリプトの実行にかかる時間を短縮することですか?

別の例としては、4つの異なるスレッドでPILを使用して4つの異なる画像をレンダリングおよび保存でき、画像を1つずつ処理するよりも速いですか?この速度の要素は、正しい用語が何であるかではなく、私が本当に疑問に思っていることだと思います。

マルチプロセッシングモジュールについても知っていますが、今の私の主な関心は小中規模のタスクロード(10〜30秒)であり、サブプロセスの開始が遅くなる可能性があるため、マルチスレッド化の方が適していると思います。


4
これはかなりロードされた質問です。答えは、スレッドにをさせたいかにあると思います。ほとんどの状況では、GILは複数のスレッドが同時に実行されるのを防ぎます。ただし、GILが解放される(ファイルからの読み取りなど)ため、並行して実行できる場合がいくつかあります。また、GILはCpythonの実装詳細(最も一般的な実装)であることに注意してください。Pythonの他の実装(Jython、PyPyなど)にはGIL(AFAIK)がありません
mgilson

2
@mgilson PyPyにはGILがあります。

2
@delnan-あなたは正しいようです。ありがとう。
mgilson 2014年

1
「サブプロセスの開始には時間がかかる場合があります」-実行の準備ができているタスクのプールを作成できます。オーバーヘッドは、タスクの動作を開始するために必要なデータをシリアライズ/デシリアライズするのにかかる時間にほぼ制限できます。
ブライアンカイン

1
@KarimBahgat、それはまさに私が言っていることです。
ブライアンカイン

回答:


132

GILはスレッド化を妨げません。GILが行うことは、一度に1つのスレッドだけがPythonコードを実行するようにすることです。制御は引き続きスレッド間を切り替えます。

そのときGILが妨げているのは、複数のCPUコアまたは個別のCPUを使用してスレッドを並列に実行することです。

これはPythonコードにのみ適用されます。C拡張機能は、GILをリリースして、Cコードの複数のスレッドと1つのPythonスレッドを複数のコアで実行できるようにします。これはselect()、ソケットの読み取りや書き込みの呼び出しなど、カーネルによって制御されるI / Oまで拡張され、Pythonがマルチスレッドマルチコアセットアップでネットワークイベントを合理的に効率的に処理できるようにします。

次に、多くのサーバーデプロイメントが行うことは、複数のPythonプロセスを実行して、OSがプロセス間のスケジューリングを処理し、CPUコアを最大限に利用できるようにすることです。ライブラリを使用することもできmultiprocessingますユースケースに適している場合を 1つのコードベースと親プロセスから複数のプロセスにわたる並列処理を処理ます。

GILはCPython実装にのみ適用できることに注意してください。JythonとIronPythonは異なるスレッド実装を使用します(それぞれネイティブJava VMと.NET共通ランタイムスレッド)。

更新に直接対処するには:純粋なPythonコードを使用して並列実行から速度を上げようとするタスクは、スレッド化されたPythonコードが一度に実行される1つのスレッドにロックされているため、速度が向上しません。ただし、C拡張とI / Oを混在させると(PILやnumpy操作など)、任意のCコードを1つで並列に実行できますアクティブなPythonスレッドます。

Pythonスレッディングは、レスポンシブなGUIを作成する場合や、PythonコードよりもI / Oがボトルネックになっている複数の短いWebリクエストを処理する場合に最適です。計算集中型のPythonコードの並列化multiprocessing、そのようなタスクのためのモジュールの使用、または専用の外部ライブラリへの委任には適していません。


@MartijnPietersに感謝します。その後、スレッド化を使用してforループなどのコードを高速化できるかどうか( "no")についての私の質問に対する明確な回答があります。多分あなたまたは誰かが私が受け入れることができる新しい回答を書くことができます。これは、スレッド化がGILによって並列実行を許可され、より高速になる一般的なモジュール/コード/操作の特定の例を提供します(例:これらのI / Oおよびネットワーク/前述のソケット読み取り操作、およびPythonでのマルチスレッド化が役立つその他のケース)。おそらく、マルチスレッドの一般的な使用法のリストと、可能であればプログラミング例をいくつか挙げてください。
Karim Bahgat、2014年

4
いいえ、そのような答えが非常に役立つとは思いません。正直に言うと。これまで完全なリストを作成することはできませんが、経験則では、I / O(ファイルの読み取りと書き込み、ネットワークソケット、パイプ)はCで処理され、多くのCライブラリもGILをリリースしています。操作を行いますが、これを文書化するかどうかはライブラリにかかっています。
Martijn Pieters

1
私の悪い、更新された答えが今まで見られませんでした。そこでは、スレッドの使用例をいくつか示しました。これらには、PythonのGUI内から1つのPythonスクリプトを呼び出すネットワークプログラミング(例:間違っている場合は修正urllib.urlopen())、複数のPIL(例Image.transform())およびnumpy(例numpy.array())の操作をスレッドで呼び出すことが含まれます。また、コメントに複数のスレッドを使用してファイルを読み取るなどの例をいくつか提供しました(例:f.read()?)。完全なリストを作成することは不可能であることを知っています。更新で指定したタイプの例が必要でした。いずれにせよ、あなたの答えを受け入れました:)
Karim Bahgat 2014年

2
@KarimBahgat:はい、urllib.urlopen()ネットワークソケットを呼び出します。ソケットI / Oを待機することは、スレッドを切り替えて他のことを行う絶好の機会です。
Martijn Pieters

4
この問題には直接関係ありませんが、スレッド化がパフォーマンスにまったく関係しない場合があることに注意してください。コードを複数の独立した実行スレッドとして記述する方が簡単な場合があります。たとえば、1つのスレッドでバックグラウンドミュージックを再生し、1つのスレッドでUIにサービスを提供し、1つのスレッドで最終的に実行する必要があるが急いでいない計算を実行する場合があります。UIランループを使用して次のオーディオバッファーの再生をシーケンスするか、または対話性を妨げないように計算を十分に小さな断片に分解することは、スレッドを使用するよりもはるかに難しい場合があります。
abarnert 2014

4

はい。:)

低レベルのスレッドモジュールと高レベルのスレッドモジュールがあります。しかし、単にマルチコアマシンを使用したい場合は、マルチプロセッシングモジュールが適しています。

ドキュメントからの引用:

CPythonでは、グローバルインタープリターロックにより、一度に1つのスレッドのみがPythonコードを実行できます(特定のパフォーマンス指向のライブラリーがこの制限を克服できる場合でも)。アプリケーションでマルチコアマシンの計算リソースをより有効に利用したい場合は、マルチプロセッシングを使用することをお勧めします。ただし、複数のI / Oバウンドタスクを同時に実行する場合は、スレッド化が適切なモデルです。


3

Pythonではスレッド化が許可されています。唯一の問題は、GILが一度に1つのスレッドのみを実行することを確認することです(並列処理なし)。

したがって、基本的にコードをマルチスレッド化して計算を高速化したい場合は、一度に1つのスレッドしか実行されないため、高速化はできませんが、たとえば、データベースとの対話に使用すると、そうなります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.