見出し画像

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ありの場合

topの表示結果

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無効化の場合

topの表示結果

GILを無効化した場合、4つのスレッドが各CPUコアでフルに稼働して、それぞれのコアで100%動作します。

処理時間も16秒に短縮されました。

$ time PYTHON_GIL=0 python test_gil.py

real    0m16.051s
user    0m52.450s
sys     0m0.028s

※あくまで仮想的な環境なので、処理時間についてはこの環境での相対的な比較としてみてください。

まとめ

GILありの場合は、図のように複数のスレッドを使っても動いているスレッドは1つだけでマルチコアの性能を活かせませんでした。

GILにより動作中のスレッドは1つのみ

それでもIO待ちのような処理ではマルチスレッドでのメリットは少しあったのですが、今後はもっと気軽にスレッドをつかって高速化ができそうです。

長い間GILによって、Pure Pythonでは並列処理が遅かったわけですが、こちらが正式導入されればPythonだけでも高速化が期待できそうです。

3.13には他にもJITコンパイラも導入されはじめ、高速化にいろいろと貢献するかもしれません。


この記事が気に入ったらサポートをしてみませんか?