福田
はじめに
2024年10月にリリースされたPython 3.
Python 3.
なお、今回の記事を書くにあたり参考にしたドキュメントは下記になります。
- Python experimental support for free threading - Python 公式ドキュメント
- Free-threaded CPython - What’s New In Python 3.
13 - PEP 703 – Making the Global Interpreter Lock Optional in CPython
- Python free-threading guide
GILとは
GILの基本概念
GILとは、複数のスレッドが同時にメモリにアクセスすることがないように、複数のスレッドでPythonインタープリターを同時に実行することを防ぐためのものです。簡単にいうと、Pythonプログラムは複数のスレッドを作成できるものの、一度に実際のPythonコードを実行できるのは1つのスレッドだけになります。
Pythonの並列処理で多くの方が制約として認識しているのが、このGILというロック機構です。
GILの利点
このGILというロック機構には、いくつかの大きな利点があります。
- メモリ管理の簡素化:Pythonのガベージコレクションとメモリ管理を簡単かつ安全に実装
- シングルスレッドパフォーマンスの最適化:複雑なロック機構を排除することでシングルスレッドの実行速度を向上
- C拡張モジュールとの互換性:C拡張モジュールがスレッドセーフではないことを考慮するため、GILによって安全性を確保
GILがもたらす制約
その反面、GILがあることによって、Pythonの並列処理では以下のような制約が生じていました。
- 真の並列処理ができない:マルチコアCPUがあたりまえの現代において、Pythonは複数のコアを効率的に活用できない
- CPU負荷の高い処理が遅い:計算集約型のタスクを並列化してもほとんど恩恵が得られない
- 並列処理のためには複雑な回避策が必要:マルチプロセスによる並列化や、C拡張を使った実装を行う必要がある
これらの制約を解消するため、Python開発チームは長年にわたってGILの撤廃や改良を検討してきました。そして、Python 3.
free threadingとは
free threadingの技術的概要
3.
技術的な特徴は以下の通りです。
- より細かい粒度のロック機構[1]:GILの代わりに、必要なオブジェクトごとに細かいロック機構を導入
- 並行ガベージコレクション:複数のスレッドでPythonプログラムが同時に実行されても安全にメモリ管理ができるガベージコレクション
- アトミック参照カウント:オブジェクトの参照カウントを原子的に操作することで、オブジェクトの整合性を保ちながらスレッド間の競合を回避
- バイアスロック:頻繁にアクセスされるオブジェクトに対して、特定のスレッドが優先的にロックを獲得できる最適化
全体のロックに代わって細かいロック機構を採用することで、スレッド間の競合を最小限に抑えつつ、並列処理の実現が可能になります。
詳細はPEP 703 – Making the Global Interpreter Lock Optional in CPythonを参照してください。
Python 3.13 free threading のインストール方法
では実際にfree threadingを体験してみましょう。以下の方法で利用が可能です。
方法1:公式ビルドをダウンロード
Python.
- Python Downloadsから最新のPython 3.
13をダウンロード - インストーラーを実行してインストール
- customizeを選択

- Free-threaded Python [experimental] を選択しインストールを行う

python3.
方法2:uvを使用する
過去の記事
$ uv python install 3.13t Installed Python 3.13.2 in 4.62s + cpython-3.13.2+freethreaded-macos-aarch64-none
また、uv run
コマンドでもPythonスクリプトを実行できます。
$ uv run --python 3.13t sample.py
なお、uvのインストールについてはこちらをご参照ください。
方法3:ソースコードからビルド
ビルドオプション--disable-gil
を有効にし、ソースコードからビルドすることも可能です。
$ sudo apt update $ sudo apt install build-essential zlib1g-dev \ > libncurses5-dev libgdbm-dev libnss3-dev libssl-dev \ > libreadline-dev libffi-dev curl clang
$ curl -O https://www.python.org/ftp/python/3.13.2/Python-3.13.2.tgz $ tar zxvf Python-3.13.2.tgz $ cd Python-3.13.2 $ ./configure --disable-gil $ make $ make install
他のコンパイルオプションについては、適宜変更してください。筆者の環境ではよく利用されるオプション、--enable-optimizations
と--with-lto
を指定してビルドできることを確認しました。
動作確認
筆者の環境では、公式よりダウンロードしインストールしたものを利用します。インストーラーを利用した場合には、python3.
$ python3.13t Python 3.13.2 experimental free-threading build (main, Feb 12 2025, 15:02:03) [Clang 19.1.6 ] on darwin Type "help", "copyright", "credits" or "license" for more information. >>>
Python 3.13のfree threadingでの動作検証
実際にfree threadingを使った並列処理のコード例を見ていきます。
動作環境
動作環境は以下のとおりです。
- Apple M2
- Sequoia 15.
3.2 - Python 3.
13. 2 / Python 3. 13. 2t
CPUバウンドな処理をマルチスレッドで実行してみる
Pythonのスレッドをconcurrent.
のThreadPoolExecutor
を使って実行します。実行するサンプルコードは以下のとおりです。
1億回繰り返す計算処理をスレッド4つで実行しています。
import concurrent.futures
import time
def cpu_bound_task() -> int:
result = 0
for i in range(10**8): # 1億回繰り返す
result += i % 10
return result
def main():
start = time.time()
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
for f in [executor.submit(cpu_bound_task) for _ in range(4)]:
f.result()
end = time.time()
print(f"Time taken: {end - start:.2f} seconds")
if __name__ == "__main__":
main()
上記のコードをPython 3.
$ python3.13 example_thread.py Time taken: 11.51 seconds
次に、free threading版で実行してみましょう。高速化されているのがわかります。3.
$ python3.13t example_thread.py Time taken: 3.57 seconds
CPUバウンドな処理をマルチプロセスで実行してみる
さて、同じ処理をマルチプロセスを使って実行してみます。先ほどのコードのThreadPoolExecutor
をProcessPoolExecutor
に変えるだけで、マルチスレッドをマルチプロセスに変えて実行できます。
import concurrent.futures
import time
def cpu_bound_task() -> int:
result = 0
for i in range(10**8): # 1億回繰り返す
result += i % 10
return result
def main():
start = time.time()
with concurrent.futures.ProcessPoolExecutor(max_workers=4) as executor:
for f in [executor.submit(cpu_bound_task) for _ in range(4)]:
f.result()
end = time.time()
print(f"Time taken: {end - start:.2f} seconds")
if __name__ == "__main__":
main()
マルチスレッドの例と同様に、3.
$ python3.13 example_process.py Time taken: 3.42 seconds
$ python3.13t example_process.py Time taken: 3.57 seconds
さて、続いて想定どおり結果に差が出たマルチスレッドで、実行する処理を変えて試してみましょう。先ほどのexample_
のcpu_
関数を変えて、どのように変化するか確認してみます。
試したパターン(すべて ThreadPoolExecutor + 4並列)
- 座標を生成して距離を計算する
def cpu_bound_task():
"""座標を生成して距離を計算する"""
points = [(x, x + 1) for x in range(1_000_000)] # 100万個の座標を生成
total = 0.0
for x, y in points:
total += (x ** 2 + y ** 2) ** 0.5
return total
- 辞書アクセスを含む計算
def cpu_bound_task():
"""辞書アクセスを含む計算"""
items = [{"x": i, "y": i + 1} for i in range(1_000_000)] # 100万個の辞書を生成
total = 0.0
for item in items:
total += (item["x"] ** 2 + item["y"] ** 2) ** 0.5
return total
- 文字列生成を含む処理
def cpu_bound_task():
"""文字列生成を含むCPUバウンドなタスク"""
total = 0
for i in range(10_000_000): # 1000万回繰り返す
# 文字列を生成して長さを計算
s = f"item-{i}"
total += len(s)
return total
それぞれ実行してみたところ、以下のような結果になりました。生成処理やdictやlistへのアクセスを含む処理の場合、free threading版のほうが遅い結果となりました。
処理内容 | ファイル名 | 3. |
3. |
---|---|---|---|
座標生成+距離計算 | example_ |
0. |
24. |
辞書のリスト生成+処理 | example_ |
0. |
25. |
f-string + len() |
example_ |
3. |
3. |
なぜ遅い場合があるのか
free threading版のPython 3.
- シングルスレッドの性能低下:free threadingを有効にすると、シングルスレッドの実行時に約40%の性能低下が見られる
- メモリ使用量の増加:細粒度のロック機構やImmortal objects[2]などの実装により、メモリ使用量が増加
シングルスレッドでの性能低下を確認するため、以下のコードの実行時間を比較してみましょう。
import time
start = time.time()
items = [{"x": i, "y": i + 1} for i in range(1_000_000)] # 100万個の辞書を生成
end = time.time()
print(f"Time taken: {end - start:.2f} seconds")
試してみたところ、既知の課題どおり、free threadingが遅いことがわかりました。
$ python3.13 example_dict.py Time taken: 0.08 seconds $ python3.13t example_dict.py Time taken: 2.21 seconds
今後の改善の方向性と新しい Python 3.14での対応
このような課題に対して、今後のPythonでは以下のような改善が予定されています。
- シングルスレッド性能の向上:現在のパフォーマンス低下は主にPEP 659: specializing adaptive interpreterが無効になっていることが原因。Python 3.
14ではthread-safeな方法でこれを再有効化する予定 - 既知の制限の解消:Immortal objectsによるメモリ使用量の増加などの既知の制限事項は、今後のリリースで対処されていく予定
今後の予定や改善点の詳細については、以下のリソースを参照してください。
- PEP 703 -- Making the Global Interpreter Lock Optional in CPython · Issue #108219 · python/
cpython - gh-115999: Update whats news for free-threaded 3.
14 by corona10 · Pull Request #131285 · python/ cpython - Make the specializing interpreter thread-safe in `--disable-gil` builds · Issue #115999 · python/
cpython
2025年3月時点での最新のアルファ版である、3.
先ほどと同じ3種類のスクリプトをPython 3.
処理内容 | ファイル名 | 3. |
3. |
3. |
3. |
---|---|---|---|---|---|
座標生成+距離計算 | example_ |
0. |
24. |
5. |
21. |
辞書のリスト生成+処理 | example_ |
0. |
25. |
1. |
0. |
f-string + len() |
example_ |
3. |
3. |
3. |
0. |
また、今回の記事では触れていませんが、free threading版では、同じスレッドで作成されたオブジェクトに対してはロックが最小限になるように最適化されています。そのため、別スレッドで対応したオブジェクトを更新しようとすると、ロックが発生し、処理が遅くなることがあります。詳細については
free threading対応状況
free threadingは実験的な機能であり、すべてのライブラリが対応しているわけではありません。とくにC拡張モジュールや、GILに依存しているライブラリは注意が必要です。free threadingに対応しているかどうか、以下のリソースを活用して確認してみましょう。
- Compatibility Status Tracking - py-free-threading:free threading対応しているOSSの一覧
- pytest-freethreaded - GitHub:free threadingに対応しているかどうかpytestで確認できるツール
まとめ
Python 3.
本記事で見てきたように、CPUバウンドな処理においてfree threadingを有効にすることで、従来のマルチスレッド処理が高速化されることを確認できました。これにより、Pythonでの並列処理の選択肢が広がり、特定のユースケースではマルチプロセスを使わずにマルチスレッドで高いパフォーマンスを得られるようになります。
ただし、実験的な機能であり課題も残っているため、プロダクション環境での採用は慎重に検討する必要があります。また、利用するライブラリのfree threading対応状況も確認しておくことも重要です。
PEPでは、段階的な移行を目指していると書かれています。長期的には、ビルド時オプションからランタイム制御へと移行し、最終的にはGILがデフォルトで無効になることが期待されています。今後のPythonのリリースでfree threadingがさらに改良され、最終的にはGILのない状態がデフォルトになる日も来るかもしれません。今後もキャッチアップしていきましょう。