Python3.13で登場したGIL無効化オプションを試してみた
概要
Python3.13からはGILを無効化してマルチスレッドプログラムが複数のコアを使用して動くモードが試験的に導入されています。
GIL(Global Interpreter Lock)とは、Python(正確にはCPython)がスレッドセーフで安全に動作するために導入されているメカニズムです。
Pythonではスレッドが利用できますが、GILの制限により複数CPUコアを使っても動くコアは1つだけ、並列処理はできません。複数のCPUコアを使用するにはmultiprocessingを使ってプロセスを複数立ち上げるしかありませんでした。
まだ試験的な導入ですが、GILを無効化したPythonでどのような動きになるか試してみます。
Python3.13tの導入
pyenvを使っていれば導入は簡単で、3.13.0rc2t をインストールしました。
$ pyenv install 3.13.0rc2t
...
$ pyenv shell 3.13.0rc2t
...
$ python -VV
Python 3.13.0rc2 experimental free-threading build (main, Sep 12 2024, 16:34:22) [GCC 13.2.0]
末尾にtがついているのがfree-threadting buildというのでGILの無効化が使えるビルドになります。
PYTHON_GIL=0という環境変数を指定して動かすことで、GILを無効化できます。
# GIL無効
$ PYTHON_GIL=0 python -c "import sys; print(sys._is_gil_enabled())"
False
# GIL有効
$ PYTHON_GIL=1 python -c "import sys; print(sys._is_gil_enabled())"
True
動作確認
以下のような単純なループ処理を4スレッドで動かすというプログラムで試します。
GILありの場合
4コアの仮想的な環境を用意して試しています。
4つのスレッドで動作するのですが、実際に動いているCPUコアは一つだけになるため、マルチコアをフル活用できません。4つのCPU使用率の合計がだいたい100%になる感じで動いています。
処理時間は40秒ほどかかりました。
time PYTHON_GIL=1 python test_gil.py
real 0m40.617s
user 0m40.685s
sys 0m0.085s
GIL無効化の場合
GILを無効化した場合、4つのスレッドが各CPUコアでフルに稼働して、それぞれのコアで100%動作します。
処理時間も16秒に短縮されました。
$ time PYTHON_GIL=0 python test_gil.py
real 0m16.051s
user 0m52.450s
sys 0m0.028s
※あくまで仮想的な環境なので、処理時間についてはこの環境での相対的な比較としてみてください。
まとめ
GILありの場合は、図のように複数のスレッドを使っても動いているスレッドは1つだけでマルチコアの性能を活かせませんでした。
それでもIO待ちのような処理ではマルチスレッドでのメリットは少しあったのですが、今後はもっと気軽にスレッドをつかって高速化ができそうです。
長い間GILによって、Pure Pythonでは並列処理が遅かったわけですが、こちらが正式導入されればPythonだけでも高速化が期待できそうです。
3.13には他にもJITコンパイラも導入されはじめ、高速化にいろいろと貢献するかもしれません。
この記事が気に入ったらサポートをしてみませんか?