Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Pythonの実行はどこまで賢くなったのか? CPythonとPyPyから見る最適化のしくみ

Pythonの実行はどこまで賢くなったのか? CPythonとPyPyから見る最適化のしくみ

Avatar for curekoshimizu

curekoshimizu

August 20, 2026

More Decks by curekoshimizu

Other Decks in Programming

Transcript

  1. Profile : 眞鍋 秀悟 ( X: @curekoshimizu ) 略歴 •

    • • • • • 京都大学 / 大学院 ◦ 入試一位合格 Fixstars ◦ Executive Engineer Mujin ◦ Architect Preferred Networks ◦ Engineering Manager Hacobu ◦ 研究開発部部長・CTO室室長 [Now] Recustomer ◦ CTO ◦ かなり長い間 Pythonを 業務で使ってきた CTO of the Year 2025, Audience Award 2
  2. 5

  3. 6

  4. 1位:型 3.10 : X | Y 3.11 : Self 3.12

    : class Foo[T] 3.13 : class Foo[T = int] 3.14 : 型アノテーション遅延評価 3.15予定 : TypeForm (型そのものの型付け) 各バージョンで確実に進化 7
  5. 性能改善 並行・並列 改善 NoGIL について 昨年 PyCon JP 2025 で

    登壇させていただきました ので そちらに関する高速化のお話 Shannon Plan は今回は割愛します GIL無効化 10
  6. ❯ uv run --python 3.14 python Python 3.14.5 (main, May

    10 2026, 19:28:16) [Clang 22.1.3 ] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import sys >>> sys._jit.is_available() True >>> sys._jit.is_enabled() False Python 3.14 JITは利用可能だが 有効にはなっていない 25
  7. ❯ PYTHON_JIT=1 uv run --python 3.14 python Python 3.14.5 (main,

    May 10 2026, 19:28:16) [Clang 22.1.3 ] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import sys >>> sys._jit.is_available() True >>> sys._jit.is_enabled() True PYTHON_JIT=1 をつけて 有効にできる 26
  8. フィボナッチ数列の計算 def fib(n): return n if n < 2 else

    fib(n - 1) + fib(n - 2) 本日はずっとこの例 53
  9. def fib(n): return n if n < 2 else fib(n

    - 1) + fib(n - 2) ソースコード ast.parse AST 54
  10. +の意味は まだ 決まっていない • “a” + “b” • 1+2 •

    1.0 + 2.0 など、 実行時に + の意味が決まる 56
  11. ソースコード AST バイトコード >>> fib.__code__.co_code 1命令 = 1B(命令番号) + 1B(引数)

    80 00 → RESUME 56 00 → LOAD_FAST_BORROW n 5e 02 → LOAD_SMALL_INT 2 38 12 → COMPARE_OP < 64 03 → POP_JUMP_IF_FALSE 80 00 56 00 5e 02 38 12 00 00 64 03 00 00 1c 00 56 00 23 00 5c 01 00 00 00 00 00 00 00 00 56 00 5e 01 2c 0a 00 00 00 00 00 00 00 00 00 00 34 01 00 00 00 00 00 00 5c 01 00 00 00 00 00 00 00 00 56 00 5e 02 2c 0a 00 00 00 00 00 00 00 00 00 00 34 01 00 00 00 00 00 00 2c 00 00 00 00 00 00 00 00 00 00 00 23 00 ※ 3.11以降は、命令の後ろに特殊化用の CACHE 領域(2バイト単位)が続く —— 右の 00 00 の連なりがその正体 57
  12. .pyc の中身を覗くと —— 同じバイト列が、そのまま居る $ python3 -c "import fib; print(fib.fib.__code__.co_code[:16].hex('

    '))" 80 00 56 00 5e 02 38 12 00 00 64 03 00 00 1c 00 $ xxd -g 1 -s 82 -l 16 __pycache__/fib.cpython-314.pyc 00000052: 80 00 56 00 5e 02 38 12 00 00 64 03 00 00 1c 00 ..V.^.8...d..... Pythonでよく見かける __pycache__/lib.cpython-314.pyc というようなファイルはこの意味! 58
  13. ちなみに —— コンパイル結果は .pyc にキャッシュされる 初回 fib.py → コンパイル →

    バイトコード → .pyc に保存 __pycache__/fib.cpython-314.pyc 2回目 以降 fib.py → .pyc を読み込むだけ(コンパイル省略) → バイトコード .pyc があるとこの部分が速くなる 59
  14. 条件分岐 fib(n=5) の場合の if (n < 2) の部分の動作 メモリー n=5

    Load Compare (<) POP_JUMP_IF_FALSE 2 5 stack 5 False 62
  15. fib(8) の計算の最後のスタックマシンの状態 fib(8) = fib(7) + fib(6) の計算 BINARY_OP (+)

    fib(6) = 8 8 fib(7) = 13 13 21 stack ここあっさり 13 + 8 = 21 をやっているが VMの中はそんなに簡単じゃない 64
  16. BINARY_OP (+) は全然簡単じゃない Python にとって + という演算は 引数によって色んな意味をもっている • •

    • • • 1+2 “a” + “b” 1.0 + 2.0 Fraction(1, 10) + Fraction(1, 20) np.array([1, 2, 3]) + np.array([4, 5, 6]) 66
  17. BINARY_OP (+) は全然簡単じゃない Python にとって + という演算は 引数によって色んな意味をもっている • •

    • • • 1+2 “a” + “b” 1.0 + 2.0 Fraction(1, 10) + Fraction(1, 20) np.array([1, 2, 3]) + np.array([4, 5, 6]) さらに __add__ という関数自体も 実行時に書き換えられている可能性も考慮する必要あり (スクリプト言語ならではの宿命) 67
  18. 今まで 特殊化適応型 インタプリタ 何用の足し算かわからないので 探しに探して 整数型用の足し算だとわかる。 だから 13 + 8

    = 21 毎回整数+整数なので 整数用の足し算を準備しておき 13, 8 が両方とも整数。 だから 13 + 8 = 21 75
  19. 複数回 fib を実行したあとの dis.dis(fib, adaptive=True) の結果 3 4 RESUME 0

    LOAD_FAST_BORROW 0 (n) LOAD_SMALL_INT 2 COMPARE_OP 18 (bool(<)) POP_JUMP_IF_FALSE 3 (to L1) NOT_TAKEN LOAD_FAST_BORROW 0 (n) RETURN_VALUE L1: LOAD_GLOBAL 1 (fib + NULL) LOAD_FAST_BORROW 0 (n) LOAD_SMALL_INT 1 BINARY_OP 10 (-) CALL 1 LOAD_GLOBAL 1 (fib + NULL) LOAD_FAST_BORROW 0 (n) LOAD_SMALL_INT 2 BINARY_OP 10 (-) CALL 1 BINARY_OP 0 (+) RETURN_VALUE 3 4 RESUME_CHECK 0 特殊化適応型 インタプリタ発動後 LOAD_FAST_BORROW 0 (n) LOAD_SMALL_INT 2 COMPARE_OP_INT 18 (bool(<)) POP_JUMP_IF_FALSE 3 (to L1) NOT_TAKEN LOAD_FAST_BORROW 0 (n) RETURN_VALUE L1: LOAD_GLOBAL_MODULE 1 (fib + NULL) LOAD_FAST_BORROW 0 (n) LOAD_SMALL_INT 1 BINARY_OP_SUBTRACT_INT 10 (-) CALL_PY_EXACT_ARGS 1 LOAD_GLOBAL_MODULE 1 (fib + NULL) LOAD_FAST_BORROW 0 (n) LOAD_SMALL_INT 2 BINARY_OP_SUBTRACT_INT 10 (-) CALL_PY_EXACT_ARGS 1 BINARY_OP_ADD_INT 0 (+) RETURN_VALUE 色々なところが 特殊化されている! 77
  20. JIT とは? 実行開始 AOT(Ahead-Of-Time) (Rust / C / Go など)

    事前に全部 コンパイル 高速実行 インタプリタ 低速実行 (CPython など) JIT (Just-In-Time) 低速実行 ホット部分を 実行時にコンパイル 高速実行 (PyPy / Java など) 時間 85
  21. CPython への JIT、挫折の20年 挑戦の歴史 (代表的なものを) 2002 2010年代 Psyco Pyston /

    Cinder 2009 Unladen Swallow 挑戦と挫折 転機 本体マージ 89
  22. 公式の挑戦記録 PEP 3146 (2010) Unladen Swallow の CPython 統合提案(Google のチーム・公式

    PEP) “This is similar to the approach taken by the current breed of JavaScript engines (V8, SquirrelFish Extreme) …” 「これは現世代の JavaScript エンジンや多くの Java VM と同じアプローチだ」 公式PEP化するものの 撤退が決まった 90
  23. コア開発者の告白 (2012) “yet another” JIT compiler の挑戦の数々... “I would like

    to write yet another JIT compiler for CPython. … I did not understand exactly why Unladen Swallow and psyco projects failed, so please tell me if you think that my project is going to fail too!” 「“また一つ”JITコンパイラを書きたい。Unladen Swallow や Psyco がなぜ失敗したのか、 正直よく分からない。——これも失敗すると思うなら、教えてほしい」 Victor Stinner — CPython コア開発者 python-dev(公式開発者ML)2012年7月17日 mail.python.org/pipermail/python-dev/2012-July/120991.html 91
  24. JIT は他では「当たり前」になっていた ブラウザから16年遅れ 1984 2002 2008 2018 Smalltalk C# /

    .NET JavaScript 元祖・実用JIT 最初からJIT Ruby Chrome の V8 MJIT→YJIT 他言語の JITの歴史 1999 2005 2012 2020 Java Lua Julia PHP 8.0 HotSpot VM LuaJIT 生まれつきJIT JIT搭載 Python JIT挑戦中 (失敗) 2002 Psyco 2010年代 2009 Pyston / Cinder Unladen Swallow 2024 Python 3.13・実験的 93
  25. 「なぜ JIT が無いのか」の声 2012 python-dev(CPython公式開発者ML)・Victor Stinner(コア開発者)・2012-07-17 “I would like to

    write yet another JIT compiler for CPython. … tell me if you think that my project is going to fail too!” 「“また一つ”JITコンパイラを書きたい。…これも失敗すると思うなら教えてくれ」 2016 Hacker News(技術フォーラム)・2016-02-18・item 11125769 “Adding a freaking JIT to CPython is a ridiculous suggestion that will never happen.” 「JITなんて馬鹿げた提案、絶対に実現しない」 2019 Hacker News・2019-09-12・item 20952620 “Is there any reason there couldn’t be a python interpreter as awesome as V8 is for JavaScript?” 「V8並みにすごいPythonインタプリタが作れない理由って何?」 2020 Hacker News・2020-09-24・item 24577040 “Could you tell us why CPython still doesn’t have JIT?” 「なぜCPythonには“まだ”JITが無いのか教えてくれ」 95
  26. 当事者 Mark Shannon の言葉 Shannon Plan の方 “CPython is slow.

    We all know that, yet little is done to fix it.” 「CPythonは遅い。みんな知っている。なのに、ほぼ何もされてこなかった」 Mark Shannon — CPython コア開発者・のち Faster CPython チーム技術リード python-dev(公式開発者ML)2020年10月20日 = Shannon Plan の書き出し mail.python.org/archives/list/[email protected](2020-10-20) 96
  27. “C をコンパイルすれば機械語になる”のに、なぜ JIT が要るのか ビルド時 —— C コンパイラが作る 実行時 ——

    JIT が作る “汎用”の機械語(=インタプリタ) “専用”の機械語 どんな .py が来ても動かせる。その代わり毎回: このプログラム・この型(int)専用。だから: fetch → switch → 箱を pop → 型チェック → 足す → 箱を確保 → push a + b 1回 = 数百命令 jo slowpath add r1, r2 ; あふれた時だけ汎用へ a + b 1回 = 2命令 あなたの .py は、インタプリタの“入力データ” —— C コンパイル時にはまだ存在しない。だから: 専用化は、実行時にしかできない。差は “C 対 機械語” ではなく “汎用 対 専用” 101
  28. なぜ“もう1本”書くことになるのか —— “+” の意味は1箇所にしかない 手書き JIT が int+int の機械語を吐くには /*

    ceval.c —— “+” の意味の定義はここだけ */ w = POP(); v = POP(); if (int と int) { 足す。あふれたら多倍長へ昇格 } else if (str と str) { 連結 } else { __add__ / __radd__ を呼ぶ } PUSH(result); 「型ガードを吐け」 int か確認が要る —— と知っている必要がある 「箱から出して ADD 1命令」 オブジェクトの箱の構造 —— を知っている必要がある 「あふれたら多倍長へ飛べ」 wrap しない、という “+” の意味の核心 —— も知っている インタプリタ = 意味の“唯一の”定義書 必要な知識 = 左の定義書、まるごと全部 だから JIT は、“意味の写し”を機械語生成の形でもう一度書くことになる —— そして2つが一致しているかは、誰も検証してくれない
  29. JIT を“手で書く”とは、どういう作業か ① ② ③ インタプリタと“同じ意味”の機械語生成器を、もう1本書く C のインタプリタとは別に、命令ごとの「x86 を吐くコード」を手書き ——

    型分岐・例外・参照カウントまで正確に。1つズレれば、黙って間違う 対象は、掛け算で増える 約150の全命令 × CPU(x86 / ARM64…)× ガード・脱最適化・レジスタ割り当て —— Psyco が x86 専用で終わった理由 Python の進化に、永遠に追従 毎バージョン、命令は増え・変わる —— インタプリタ側の変更を JIT 側へも手で移植し続ける、終わりのない“二重保守” 同じ“Python の意味”を、2つの形で保守し続ける —— CPython 本体に JIT が入ったのも、この“手書き”をやめられたから(copy-and-patch) 103
  30. Psyco の中の a + b Psyco のソースコード抜粋(..... は中略) /* ①

    c/Objects/pintobject.c(実物・抜粋) */ static vinfo_t* pint_add(PsycoObject* po, vinfo_t* v, vinfo_t* w) { CONVERT_TO_LONG(v, a); /* int? 検査+箱外し */ x = integer_add(po, a, b, true); ..... /* overflow → CPython の nb_add へ退避 */ /* ② c/i386/iencoding.c */ BEGIN_CODE COPY_IN_REG(v1, rg); /* MOV rg,(v1) */ COMMON_INSTR_FROM(group, rg, /* ADD rg,(v2) */ v2->source); END_CODE if (ovf && runtime_condition_f(po, CC_O)) return NULL; /* あふれ検知も自前 */ ① 型ガードも“退避路”も、自分で設計 int か検査して箱外し、あふれたら CPython へ退避 —— 型の“意味の再実装”だけで 約9,200行 ② レジスタ割り当ても、あふれ検知も自前 ADD 1命令のために MOV・フラグ管理・レジスタ確保 —— コード生成の共通土台で 約5,900行 ③ 命令バイトを、1バイトずつ直書き 0x83 は ADD の命令番号。ModRM バイトも手計算 —— x86 一式 約3,000行のうち、生バイト書きは 約1,500 行 /* ③ c/i386/iencoding.h */ code[1] = 0xC0 | (group<<3) | (rg); code[2] = (code_t) _v; code[0] = 0x83; code += 3; ..... 104
  31. 単価 17行 × 88実装 a + b(int+int)の1実装ぶん 約100行 (本体17行+ヘルパ・定型) ×

    88実装(演算 × 型) 意味の再実装ぶん ≈ 9,200行 c/Objects/ の実測値 int・float・str・list・dict… 40ファイル さらに「命令」ごとに作る必要あり 105
  32. JIT 手書きの“見積書” CPUアーキテクチャ個数 x86 32bit だけの保守だけでこの量 意味の再実装(演算×型 88実装) 9,200 行

    バイトコード命令ごとの特殊化 3,200 行 コード生成の土台(共通) 5,900 行 特殊化コア・フレーム管理 ほか 10,700 行 x86 依存ぶん一式(CPU 1つあたり) 3,000 行 合計 出典: psyco-1.6-src(SourceForge) 約 32,000 行 Pythonのデータの持ち方が変 わったりするたびに修正が必須 これを頑張ったが 力尽きたのが Psyco 106
  33. Psyco の教訓 JITコード を “手で書き続ける”のは 保守が難しすぎる x86 だけでこの量になってしまった... 作者 Armin

    Rigo は保守を断念 —— のちに“機械に書かせる”道(PyPy)を、自ら作りに行く 107
  34. stencil =「部品機械語テンプレート」を 実行時に不定箇所だけ埋める (概念図) ビルド時に用意した stencil mov 実行できる機械語 rax, [rsp-8]

    test rax, rax add rax, 0xDEADBEEF jne 0xDEADBEEF 赤 = 埋めるべき「穴」 mov コピー& パッチ → rax, [rsp-8] test rax, rax add rax, 0x7f3a20 jne 0x55d1c8 黄 = 実行時の値で埋めた 112
  35. 20年かけて“保守できる形”へ 挑戦の歴史 2002 2010年代 2021 Psyco Pyston / Cinder Copy-and-Patch

    論文 32bit専用で限界 本体外で発展 「本体が飲める形」 2009 2020 2024 Unladen Swallow Shannon Plan 3.13 実験JIT導入 LLVM採用/5倍目標は未達 JITはStage 3-4に明記 → 3.14 同梱・初期は無効 挑戦と挫折 転機 本体マージ 118
  36. fib(43)の速度比較 JIT ON / OFF を同一バージョンで比較 このfibでは、3.14 の JIT の効果は出ていない

    122 AMD Ryzen 7 8700G・Ubuntu 24.04LTS・RAM 128GB・CPythonは uv ビルド(python-build-standalone)
  37. 3.14 の JIT、公式計測でも“効く形”はある 公式ベンチ基盤 faster-cpython/benchmarking-public の JIT オン/オフ比較(ベンチ別) richards −17%

    deltablue −9% spectral_norm −5% nbody −2% go +12% ← 速くなる 遅くなる → 出典: faster-cpython/benchmarking-public(linux-x86_64・3.14.0a7+・commit 7363e8d・2025-05-03・JIT vs base) 全体(pyperformance の幾何平均)は 1.002x faster = ほぼ中立 —— “効く形”と“効かない形”がある 126
  38. PyPy = 別実装のPython実行系 有名なPython実行系たち (Pythonファイルを実行できる) • • • • •

    • CPython : Pythonといえばこれ PyPy MicroPython Jython IronPython PyPy : 使い方は pypy3 main.py と打つだけで … CPython で動作していたものを動かせる 135
  39. fib(43)の速度比較 このfibでは、PyPy が CPython 3.11 の約10.7倍 137 AMD Ryzen 7

    8700G・Ubuntu 24.04LTS・RAM 128GB・CPythonは uv ビルド(python-build-standalone)
  40. PyPy 小史: JIT は2010年に実った 2003 〜2009 PyPy 誕生 JIT 生成器、3度失敗

    「Python で Python を」 「もうすぐ出る」が、出ない 2004–07 2010 EU が研究資金 JIT 搭載(PyPy 1.2) FP6・28ヶ月の公費研究 speed.pypy.org 開設 現在は PyPy 7.3 Python 3.11 互換 139
  41. インタプリタ専用言語 RPython を開発 インタプリタ(解釈する係) それを書いた言語 CPython ceval.c などの C コード

    C 言語 PyPy pyopcode.py などの RPython で書かれたコード RPython (Restricted Python) RPython のコードは Python として動く。だが、普通の Python は RPython として実行できない 制限 (Restricted) 例:1つの変数に、複数の型を入れてはいけない/グローバルは定数扱い
  42. RPython の仕組み (全体地図) : 保守簡単 RPythonで書かれた インタプリタ 型がすべて推論可能 translator (Pythonで書かれている)

    が JIT・GC 機能も追加して変換 RPythonコードはCPythonでも 動くコード体系なので CPython でテストもできる C コード (自動生成) pypy 実行バイナリ (JIT 内蔵)
  43. インタプリタだけ書いて JIT を手に入れる 1. brainfuck のインタプリタをRPython で書く 2. rpython --opt=jit

    bf.py 3. JIT付きバイナリを得る! brainfuck 用の JIT コンパイラは 何も書いていないことに注意! 152
  44. mandelbrot.b の速度比較 インタプリタを CPython で動かす vs インタプリタをバイナリまで変換したもの (JITあり・なし) 153 AMD

    Ryzen 7 8700G・Ubuntu 24.04LTS・CPython 3.14.7・PyPy 7.3.23 の rpython で翻訳・mandelbrot.b は Erik Bosman
  45. PyPy は JIT コンパイラ でもある “PyPy 1.0: JIT compilers for

    free and more” 「PyPy 1.0 —— JIT コンパイラを、タダで。ほかにも色々」 “PyPy is now also a Just-In-Time compiler generator.” (PyPy はもう、JIT の“生成器”でもある) doc.pypy.org/en/latest/release-1.0.0.html 154
  46. 発想の根本的な違い CPython の JIT PyPy(メタトレーシング) 観測するのは、 あなたのプログラム(fib) → fib 専用の機械語を作る

    観測するのは、 「fib を実行中のインタプリタ」 → インタプリタごと特化した機械語 156
  47. 実は、CPython の JIT と同じ思想 機械語生成を手で書かない —— インタプリタの定義から、自動で得る CPython(copy-and-patch) PyPy(メタトレーシング) ビルド時に、インタプリタのソース

    (uop 定義)から機械語テンプレを生成 実行時に、インタプリタの動きを 観測して機械語化 違うのは「いつ・どうやって」だけ。「誰が書くか(機械が)」は同じ Armin Rigo たちは、同じ答えに 20年早く辿り着いていた 157
  48. 同じ言語、まったく別のエンジン CPython PyPy 実装 C を人間が手書き RPython で書き、C を自動生成 実行エンジン

    インタプリタ+JIT(3.13〜・実験) インタプリタ+JIT 標準装備(2010〜 ) メモリ管理 参照カウント(+循環 GC) 世代別トレーシング GC —— 参照カウン トは無い C API 本家(PyObject* そのもの) cpyext で変換 ——「弱点」の根はここ “Python の約束”は同じ。守り方が、全部違う 158
  49. CPython の“別実装”とは 同じもの = “Python 互換” 違うもの = CPython の“中身”

    文法・言語の意味・標準ライブラリ あなたの .py は、同じ結果で動く C API / ABI(PyObject*)・参照カウント バイトコード・メモリ上のオブジェクト配置 = 言語仕様が保証する範囲 = 誰も保証していない内部実装 「Python 互換」と「CPython 互換」は、別の約束 —— PyPy が名乗れるのは前者まで 163
  50. 弱点①: 色々なエコシステムは CPython の ABI の上にある 実はここが CPythonの 強みだったりする CPython

    あなたのコード → C API/ABI(本家) → NumPy・DB ドライバなど 大量の C 拡張 PyPy あなたのコード → cpyext(互換レイヤ) → 同じ C 拡張 動くが遅い PyPyはNumPyなどのエコシステムが 遅いという問題 165
  51. 実測: NumPy を挟むと PyPy は負ける 1.94秒 # 100要素の dot を

    100万回 import numpy as np a = np.arange(100, dtype=np.float64) b = np.arange(100, dtype=np.float64) total = 0.0 for _ in range(1_000_000): total += float(np.dot(a, b)) 0.41秒 CPython 3.11 PyPy 7.3.22 (3.11互換) PyPy が 約4.7倍 遅い cpyext の往復コストが、JIT の速さを食い潰す JIT ウォームアップ後・3回実行の最小値・環境は fib(43) の計測と同一(AMD Ryzen 7 8700G・Ubuntu 24.04) 166
  52. 実測: 軽い仕事でも PyPy は負ける 38 ms # fib(25) を1回だけ計算して終了 def

    fib(n): return n if n < 2 else fib(n-1) + fib(n-2) 18 ms print(fib(25)) CPython 3.11 PyPy 7.3.22 PyPy が 約2倍 遅い 起動と JIT の助走を、回収する前に終わる プロセス起動〜終了の実時間・7回実行の最小値 | ※ fib(28)(約0.04秒)で逆転、fib(30) 以降は PyPy の圧勝 —— 分岐点を越えるかが全て 168
  53. PyPy の使いどころ ◎ 純 Python のホットループが、長く回る処理 △ Web API ボトルネックが

    DB / IO なら、Python が3倍でも全体は数% × 今日のベンチマーク fib はこのタイプ だったので高速 C 拡張ヘビーな処理・短命プロセス Numpy を多く使う科学技術計算は cpyext の壁 169
  54. sum ループ(N = 10⁸)の速度比較 Numba 速すぎる! 177 total += i

    を1億回・4構成とも同じ答え・Numba は LLVM が N(N-1)/2 に閉形式化 = O(1)・環境は fib(43) と同一
  55. LLVM概要 gcc(C) clang(C) rustc(Rust) (独自言語) ↓ ↓ ↓ ↓ 専用最適化器

    LLVM ↓ ↓ バイナリ バイナリ めっちゃ色々な 最適化手法が ここにあるので このエコシステムに載れると 独自最適化をかかなくていい 183
  56. みんな、同じ LLVM clang(C) rustc(Rust) Numba(@njit) ↓ ↓ ↓ LLVM ↓

    “証明”の最適化 —— ループを、答えの式 N(N-1)/2 に置き換える 184
  57. N = 10 ** 10 # 0〜N-1 の総和 total =

    0 for i in range(N): total += i 49999999995000000000 (正解) -5340232226128654848 (不正解) CPython・PyPy Numba 186
  58. PEP 836 抜粋 However, many users cannot adopt an alternative

    runtime even when it may perform better on their code due to factors such as supported Python versions, extension compatibility, embedding requirements, deployment constraints, and tooling support. 「多くのユーザーは、たとえ速くても代替ランタイムへ移れない —— バージョン・拡張互換・組込み・デプロイ・ツールの理由で」 193
  59. 高速化への要望と近年の進捗 Python 3.13 JIT 実験的 free-threading (NoGIL) 実験的 Python 3.14

    JIT 同梱! デフォルトはOFF free-threading (NoGIL) 同梱! デフォルトはOFF ※ 3.14 時点では free-threaded ビルド上で JIT は使えない —— 併用は次ページ PEP 836 のロードマップ 196
  60. PEP 836 への期待! “not the JIT or free-threading, but rather,

    the JIT and free-threading” 「JIT か free-threading か、ではない。JIT と free-threading、だ」 “まだ賢くなる”は願望ではない —— 期限と数値つきで、いま審議中 PEP 836 “JIT Go Brrr” Draft・2026年7月2日(Ostrowski / Ken Jin / Bucher) 3.17 β1 までに free-threaded 上で幾何平均 +20% → “実験的”卒業を目指す。 3.16 で frontend をメソッド方式へ移す提案も柱 197