バックエンドエンジニアの小門です。
この記事ではグローバルインタプリタロック (GIL) が解消されたPythonを動かしてみた検証の方法と結果について書きます。
なおGIL自体の説明や詳しい仕組みについてこの記事ではほとんど説明しないのでご了承ください。
準備として開発バージョンを取得してソースコードからビルドし、ビルド成果物のPythonランタイムを使って検証します。
準備(ビルド)
Pythonにおける「GIL廃止」の第一歩として、CPython本家のリポジトリにおいてGILを無効化できるようにするための修正が2024年3月12日mainブランチへマージされました。
gh-116167: Allow disabling the GIL with PYTHON_GIL=0 or -X gil=0 #116338
また同日、上記の変更を取り込んだ開発バージョンが v3.13.0a5 としてリリースされました。
https://www.python.org/downloads/release/python-3130a5/
https://github.com/python/cpython/releases/tag/v3.13.0a5
まだ開発途中のアルファ版ですが、今回はこのバージョンを使って検証していきます。
なお筆者の動作環境は以下の通りです。
- CPU: AMD Ryzen 7 3700X(8コア)
- OS: Ubuntu 22.04 (on WSL2 / Windows10)
- gcc: 11.4.0
また、本記事の手順ではソースコードをビルドするためのツール群が必要になります。
お使いの環境に応じて必要な準備をしてください。
参考: Python Developer's Guide - Setup and building
ビルド/インストール手順
GILを無効化するにはビルド時にオプションを指定しておく必要があります。
オプションは--disable-gil
とのこと。分かりやすいですね。
https://github.com/python/cpython/blob/076d169ebbe59f7035eaa28d33d517bcb375f342/configure#L1815-L1816
一連のコマンド手順は以下のようになります。
$ pwd /home/skokado/playground-py313 $ # インストール用ディレクトリを作成 $ mkdir -p local/python-3.13 $ # ソースコードを取得 $ wget https://www.python.org/ftp/python/3.13.0/Python-3.13.0a5.tgz $ tar xf Python-3.13.0a5.tgz $ cd Python-3.13.0a5/ $ # オプションの確認 $ ./configure --help | grep gil --disable-gil enable experimental support for running without the $ # ビルド、インストール $ ./configure --disable-gil --prefix $(pwd)/../local/python-3.13 && make install checking build system type... x86_64-pc-linux-gnu checking host system type... x86_64-pc-linux-gnu checking for Python interpreter freezing... ./_bootstrap_python ... (略) Successfully installed pip-24.0 $ # インストールできたことを確認 $ cd ../local/python-3.13 $ ./bin/python3.13 -VV Python 3.13.0a5 (main, Mar 14 2024, 18:37:25) [GCC 11.4.0]
ベンチマーク検証
GILはCPUバウンドなマルチスレッド処理において実行可能なスレッドが制限されるものです。
したがってマルチスレッド処理を行うスクリプトで実行結果を比較してみます。
検証スクリプトは以下です。
# test_gil.py from concurrent.futures import ThreadPoolExecutor import time import math def get_primes(max: int) -> list[int]: # (あえて低速な) n以下の素数一覧を返す関数 if max < 2: raise ValueError() primes = [2] for n in range(3, max + 1): is_prime = True for i in range(2, int(math.sqrt(n)) + 1): if n % i == 0: is_prime = False break if is_prime: primes.append(n) return primes if __name__ == "__main__": print("concurrency,time") for concurrency in range(1, 10 + 1): start = time.monotonic() with ThreadPoolExecutor(max_workers=concurrency) as executor: futures = [executor.submit(get_primes, 500000) for _ in range(concurrency)] for f in futures: f.result() end = time.monotonic() duration = end - start print(f"{concurrency},{duration:.2f}")
- 「CPUバウンド処理」として素数判定をメインにした関数をThreadPoolExecutorでマルチスレッド処理する
- ※引数
max
は筆者の環境で1、2秒程度かかる値を選択
- ※引数
concurrency
で指定されたスレッド数分だけget_primes
を並列に起動するconcurrency
を1から10まで変化させて所要時間を計測する- ※それぞれ3回ずつ実行し、平均時間を取得
ちなみに、上記でビルドしたv3.13.0a5において実際の処理でGILを無効にするには環境変数PYTHON_GIL=0
とともに実行する必要があります。
$ PYTHON_GIL=0 ./bin/python3.13 test_gil.py
結果
比較対象は以下の通りです。
v3.12.2
: 執筆時点の最新リリースバージョンv3.13.0a5
: "--disable-gil" オプション無しでビルドしたランタイムv3.13.0a5 & --disable-gil
: "--disable-gil" オプション付きでビルドかつ "PYTHON_GIL=0" 無しで実行v3.13.0a5 & --disable-gil & PYTHON_GIL=0
: GILを無効化して実行
(単位: 秒)
cocurrency | v.3.12.2 | v3.13.0a5 | v3.13.0a5 & --disable-gil | v3.13.0a5 & --disable-gil & PYTHON_GIL=0 |
---|---|---|---|---|
1 | 1.12 | 1.01 | 1.47 | 1.46 |
2 | 2.29 | 2.07 | 3.00 | 1.56 |
3 | 3.46 | 3.13 | 4.56 | 1.74 |
4 | 4.62 | 4.17 | 6.02 | 1.78 |
5 | 5.74 | 5.22 | 7.37 | 1.98 |
6 | 6.91 | 6.35 | 8.82 | 2.06 |
7 | 8.08 | 7.40 | 10.29 | 2.23 |
8 | 9.22 | 8.42 | 11.84 | 2.40 |
9 | 10.38 | 9.47 | 13.26 | 2.56 |
10 | 11.53 | 10.52 | 14.80 | 2.71 |
GIL無効化(--disable-gil
オプションでビルトかつPYTHON_GIL=0
)の場合のみ所要時間が並列度に単純比例せず、期待した結果となりました。
また、GILが有効なv3.12.2
とv3.13.0a5
では単純に約10%程度高速になりました。
バージョンアップに伴って性能が改善されるのは嬉しいですね。
一方非マルチスレッド処理(concurrency=1
)においては性能が悪化しました。
上記の検証スクリプトの場合、データ構造の安全性に関するオーバーヘッドの影響が考えられます。
PythonでGILの排除が難しい理由として、参照カウントの存在に加えて、Pythonインタープリタが辞書やリストなどの複雑なコレクションに依存している、という点もよく挙げられます。
残念ながら、手放しに喜べる検証結果とはなりませんでした。
今後のベータ版やrc版でも引き続き検証してみたいです。
まとめ
Python3.13の開発バージョンを用いてのGILの解消を確認しました。
プロセスあたりのマルチスレッド処理の性能向上が期待できますね。
GILの解消を提案したPEP 703によるとターゲットバージョンはPython3.13であり、順調に開発が進めば2024年10月にリリースされることになりそうです。
参考