Pythonの標準ライブラリは、マルチスレッドのためのthreadingモジュールを提供しています。スレッドは、1つのプロセス内で複数の操作を並行して実行することを可能にします。しかし、Pythonの標準実装(CPython)には**GIL(Global Interpreter Lock)**というメカニズムがあります。これは、Pythonのバイトコードを同時に実行できるスレッドを1つだけ許可するグローバルなインタープリタロックです。
これはつまり、CPythonにおいてはマルチスレッドがCPUレベルでPythonコードの真の並列性を達成できないことを意味します。並列性は、入出力待ちに関連するタスク(I/O-bound)にのみ有用です。CPU負荷の高いタスクについては、multiprocessingモジュールを使用することをお勧めします。これは、いくつかのプロセスを起動し、GILを回避します。
例:
import threading def worker(): print('開始') # 重い計算 print('終了') threads = [threading.Thread(target=worker) for _ in range(5)] for t in threads: t.start() for t in threads: t.join()
集中的な計算のための並列処理には、multiprocessingを使用してください:
from multiprocessing import Pool def square(x): return x*x with Pool(4) as p: print(p.map(square, [1, 2, 3, 4]))
Pythonのマルチスレッドで計算集約的なタスクの実行速度を上げることはできますか?
回答: いいえ、GILのためにPythonの標準実装(CPython)では、スレッドはCPU負荷の高いタスクではパフォーマンス向上をもたらしません。そのようなタスクには、multiprocessingやGILを持たない他のインタープリター実装(例えば、JythonやIronPython)を使用してください。
物語
大規模データ処理プロジェクトで、チームはスレッド(
threading)を使用して計算を加速しようとしました。代わりに、GILのためにスレッドが並行して動作できなかったため、作業時間が増加しました。multiprocessingに切り替えた後、問題は解決されました。
物語
開発者は大きなファイルを同時にダウンロードし、それをいくつかのスレッドで処理しようとしましたが、ロックなしに共有変数を不注意に使用したため、よく「デッドロック」に遭遇しました(スレッドの安全性)。
物語
バックエンドサーバーで、重いリクエストの処理がスレッドプールで実装されました。負荷が増加するにつれて、サーバーが「フリーズ」し始めました。GILのため、スレッドの大部分がPythonコードの実行を待つ時間に費やされていましたが、リクエストは集中的なI/Oに関連していませんでした。