- Python Steering Councilが PEP 703 を受け入れる意向を示し、CPythonのGIL削除は実験的ビルドからデフォルトモードへの移行まで、長い段階的プロセスに入った
- GIL削除はマルチスレッド性能を開く可能性がある一方、既存エコシステムの大半を占める シングルスレッド性能 とC拡張の互換性にコストを生じさせる可能性がある
- Faster CPythonチームは、PEP 659ベースの Specialized Adaptive Interpreter がGILに依存しているため、no-GIL環境では最適化戦略と保守負担を再計算する必要があると見ている
- MetaはPEP 703が受け入れられた場合、2025年末までに 3 engineer-years を投入すると表明し、Anacondaはpip、cibuildwheel、conda-forgeなどのパッケージング作業の支援を約束した
- 移行はPython 2→3のときのような断絶を避ける方向で進められ、no-GILの混乱が利益を上回ると判断されれば、デフォルトモード宣言前まで撤回される可能性がある
PythonのGIL削除論議が再び本格化
- Pythonの Global Interpreter Lock(GIL) は、一度に1つのスレッドだけがPythonコードを実行できるよう、インタプリタ仮想マシンへのアクセスを直列化する
- 複数スレッドを活用した性能向上を妨げてきたGILは、Pythonの長年の弱点としてたびたび挙げられてきた
- Sam Grossは2021年10月に no-GIL Python概念実証版 を公開したが、初期の関心のあと1年以上は進展が限定的だった
- その後、Python Steering Councilは no-GIL機能を受け入れる意向 を発表した
- 実際のリリース版に入るまでには時間がかかる
- 将来のどこかの時点で作業が撤回される可能性も残っている
- 複数企業の支援によって成功の可能性は高まっている
Faster CPythonとシングルスレッド性能の緊張関係
- 2022年のPython Language Summitで、Grossは no-GIL fork を発表し、作業継続について暗黙の合意を得ようとしたが、詳細な影響が十分に知られておらず、合意には至らなかった
- 同じ時期に Faster CPython プロジェクトは、インタプリタのシングルスレッド性能向上に注力していた
- Mark Shannonは PEP 659 「Specialized Adaptive Interpreter」を執筆し、この変更の一部はPython 3.10と3.11に入った
- PyConでは、Faster CPythonチームのBrandt Bucherが適応型命令を、Shannonがメモリレイアウト改善やその他の最適化手法を発表した
- 既存のPythonプログラムはGILのためにほとんどがシングルスレッドで書かれているため、シングルスレッド性能の向上 はPythonエコシステム全体の体感性能に直接影響する
PEP 703提案と初期の懸念
- Łukasz Langaは2023年1月、Grossが作成した PEP 703 「Making the Global Interpreter Lock Optional in CPython」の初版を公開した
- no-GILへの期待とともに、Cで書かれたPython拡張モジュールが主要な懸念として浮上した
- GILはC拡張コードで多くの並行性問題を防ぐ役割を果たしてきた
- GIL削除はそのコードに新たなバグを生む可能性がある
- Python 2から3への移行時のような flag day移行 は避けるべきだという共通認識があった
- GIL削除への移行は、まだ準備できていないコードとも滑らかに動作しなければならない
- Shannonはシングルスレッドコードで許容可能な性能低下がどの程度かを問い、自身の見積もりとして 15〜20% の範囲を挙げ、PEP 659への影響次第ではさらに大きくなる可能性があると見た
- Eric Snowは、PEP 684「Per-Interpreter GIL」とPEP 683「Immortal Objects」を書いた立場から長文の分析を投稿し、no-GILとサブインタプリタ方式は必ずしも衝突しないと見ていた
C拡張に生じるコストと利益
- Grossは、C拡張への影響が全面的にマイナスというわけではないと答えた
- PEPには、広く使われるC API拡張のメンテナがGIL回避作業で経験している複雑さに関する引用が含まれている
- PyTorchコア開発者のZachary DeVitoは、ここ数か月の間に実際の問題解決よりも GIL制約の回避 を理解することに一桁多い時間を3回も費やしたと述べた
- no-GILは拡張モジュールのメンテナに新たな並行性問題を生む可能性がある一方で、GIL回避のための複雑さを減らすことにもつながる
更新版PEPと性能論争
- Grossは2023年5月初旬、Python 3.12開発版に基づく PEP 703実装 と更新版PEPを公開した
- 5月12日にはSteering CouncilにPEPの判断を求めたが、決定までさらに議論が続いた
- 6月2日、ShannonはPEPの性能影響を評価し、11〜30% の範囲の影響を示したが、この数値は論争を呼んだ
- Shannonは、適応型特殊化インタプリタがGILに依存しているため、no-GILが受け入れられれば最適化戦略を再設計する必要があると見ている
- 再設計と実装に使う労力は、実際の最適化作業には投入できない
- LangaはShannonの見積もりより影響がはるかに小さいことを示すベンチマーク結果を公開し、追加結果もGrossがPEPで報告した内容に近かった
Python 2→3移行から得た教訓
- Guido van Rossumは、Python 2と3のコードが同じインタプリタ上で共存できていれば、移行の助けになっただろうと考えている
- no-GILを進めるなら、GILを必要とする拡張モジュールもno-GILインタプリタで追加作業なしにimportできなければならないと強調した
- アプリケーションコードも修正不要であるべきだ
- 拡張モジュールも修正不要であるべきだ
- Steering CouncilのGregory P. Smithは、PEP 703の影響範囲が非常に大きいため、即断できる段階ではないと述べた
- Smithは需要があることは認めつつも、エコシステム全体を考慮し、世界を壊さない移行方法を見つける必要があると考えている
- Grossは、明確な受け入れ基準と日程なしに判断を先送りすれば、実質的には「no」と同じように機能すると反応した
Faster CPythonチームが見る3つの選択肢
- Shannonは「A fast, free threading Python」という議論の中で、今後の選択肢を3つに整理した
- 従来計画どおり高速なシングルスレッドインタプリタを追求する
- シングルスレッド性能に未知だがゼロではない影響を与えるno-GIL free-threadingインタプリタを追求する
- 両方を同時に追求する
- Shannonは、性能・並列性・可変性のうち何を制限するかを選ぶ必要があると見ている
- 「Performance, parallelism, mutability: pick two」ではなく、「pick one to restrict」に近いと表現した
- free-threading環境でPythonを高速化するには 独創的な研究 が必要で、コストとリスクがより大きいと警告した
- 望ましいのは3番目の選択肢だが、no-GILだけを選んで「誰かが性能問題を解決してくれる」と期待してはならないとした
- van Rossumも、free threadingと高速なper-thread性能の両立が最善だと考えているが、追加リソースが必要だと強調した
企業支援とコア開発者の世論
- van Rossumは、MicrosoftがFaster CPythonチームへの支援を継続しており、このチームの役割はシングルスレッド性能改善に限られないと述べた
- no-GILの世界に合わせて特殊化と最適化作業を調整し、最終的にはシングルスレッド性能低下なしでno-GILを唯一のビルドモードにすることを目標として示した
- MetaのCarl Meyerは、PEP 703が受け入れられた場合、Metaが2025年末までに 3 engineer-years を投入すると述べた
- CPython内部に詳しいエンジニアがコア開発チームと協力する
- PEP 703実装をCPythonへ滑らかに反映する
- no-GIL CPythonの互換性と性能改善を継続する
- AnacondaのStan Seibertは、PEP 703採用に伴うパッケージング問題を支援すると述べた
- pip、cibuildwheel、conda-forge関連の作業を含む
- no-GIL対応パッケージをPythonコミュニティに届けるために必要な作業を含む
- コア開発者アンケートでは、46人中 87% がfree-threaded Pythonを積極的に推進すべきだと答え、38人中 63% がPEP 703ベースのno-GIL Pythonの支援と保守に貢献する意思があると答えた
Steering Councilの決定と段階的移行
- 7月28日、Thomas WoutersはSteering CouncilがPEP 703を受け入れることを決めたが、受け入れの詳細はまだ作業中だと発表した
- まずno-GILインタプリタを導入して不足部分を把握し、no-GILがデフォルトとなり最終的に唯一の版になる前に必要な作業を埋めていく方針である
- 移行期間は約 5年 と見積もられている
- CouncilはPython 3のような状況を望んでおらず、no-GILビルドに合わせるために必要なサードパーティコード変更はwith-GILビルドでもそのまま動作すべきだと考えている
- 短期的には、Python 3.13の時点になり得る実験的no-GILビルドが提示されている
- Python 3.13は2024年10月の予定
- コア開発者やその他の人々が実験できるビルド
- 中期的には、no-GILはデフォルトではないサポートオプションになる
- 時期はコミュニティがno-GILビルドをどれだけ速く採用・支援するかに大きく左右される
- 長期的には、no-GILがデフォルトビルドとなり、GILは完全に削除される
- 不必要に後方互換性を壊さない方法で進める必要がある
まだ終わっていない作業
- Woutersは、GIL削除はPEPを1本受け入れるよりはるかに大きな仕事だと見ている
- コア開発者たちはno-GIL Pythonの経験を積み、それを基に残りのコミュニティを導いていく必要がある
- 既存コードのスレッド安全性を整理する過程で、新たな C APIとPython API が必要になる可能性がある
- 全過程を通じて、進捗と日程を定期的に再評価しなければならない
- さらに10年続く後方互換性の争いにしてはならない
- PEP 703が問題になると見えたら中断し、別の解決策を探せるようにすべきだ
- no-GIL-only Pythonに至るまでには、研究、コーディング、テスト、実験、文書化がまだ大量に残っており、例として2028年10月になり得るPython 3.17が言及されている
1件のコメント
Hacker Newsの意見
記事はよく書けていて全体の経緯もうまく整理されているが、GIL撤廃への反対側と失敗の可能性にやや重きを置いている
反対側についても十分に強調する必要がある。Sam Grossの作業品質は非常に高く、no-GILと直接関係のない性能改善も盛り込んで性能低下を抑えた。オープンソース方式でも非常にうまく進めており、コミュニティからの圧力がなければ運営委員会でずっと寝かされていたであろうほど反応が遅かったにもかかわらず、忍耐強さを見せた。サブインタープリタは、Pythonでの有用性、とりわけ本格的な指標を示した例がこれまでほとんどなく、今回がよく定義され測定された初の試みに近い。コミュニティの反応もこのプロジェクトへの大きな関心を示し、運営委員会も「PEP 703を受け入れる意向があり、受諾の詳細条件を調整中」と結論づけた。no-GILの熱心な支持者というわけではなく、最終的に撤廃されなくてもかまわないし、サブインタープリタを先に試すべきだと思っているが、公平に見る必要がある
結果もかなり印象的だ: https://lwn.net/SubscriberLink/941090/8bcb029dbf548f26/。期待できる範囲では十分よい出来に見える。サブインタープリタの作業はfree-threadingの作業と並行して進むようで、両者はユースケースが異なる
PDMはまだ対応していると理解している。ビルドと配布にvirtualenvを使うのが嫌で、PythonもJavaScriptのように動作できればいいと思う。それが可能であることはすでに証明されている。議論スレッドはhttps://discuss.python.org/t/pep-582-python-local-packages-d...にある。「正しい方法はただ1つだけ」が却下理由のように使われるのももどかしいが、Pythonでその言葉が真実だと感じたことはない
LWNの素晴らしい記事で、読む価値が大いにあった。Sam GrossのNoGILが最初に出てきたときは期待していたが、記事を読み、自分の経験を振り返るうちに考えが変わり始めた
複数の言語でバックエンドシステムを作ってきたが、おおむね2種類しかなかった。1つはネットワークエンドポイントを開き、リクエストを受けて計算や別のネットワークリクエストを経て応答するシステムで、もう1つはキューやデータベース、他のAPIのポーリングなどからメッセージを読み取り、計算とネットワーク呼び出しを行ったうえで別のキューへ送るシステムだ。前者ではレイテンシが重要で、後者ではスループットが重要になる。前者のタイプでは、リクエストに応じてスレッドを立て、計算の重いエンドポイントが他のリクエストを妨げず、データベース接続プールを共有したいのでNoGILは有用だ。後者のタイプでは、GILのない言語でも、共有リソースを持つプロセス内並列性や並行性を使った記憶はほとんどなく、理解するのが難しすぎる。最適化はたいてい賢いバッチ処理で、並列性は複数の独立プロセスを複数のマシンで動かす形だった。NoGILのせいで後者のタイプのシステム品質が妥協されるなら、かなり残念に思うだろうし、実際いま精神的エネルギーの大半は後者のタイプの改善に使っている
現在はQThreadでJournalParserを実装しており、このパーサはElite: DangerousとOdysseyが生成するプレイヤージャーナルファイルからゲームイベントを継続的に読み取り、イベントごとにカスタムQSignalを発生させ、そのSignalを待ち受けるスロットが処理する。アプリケーションの他の部分でも、GILがなければかなり役立つ可能性がある。https://captainslog.scarygliders.net/captains-log-2/
そうなれば、みんなのコードが良くなり得る
もちろん、CPU中心のプログラムをそもそもPythonで書くべきではないと言うこともできるが、それはまた別の話だ
共有リソースが読み取り専用なら、なぜ混乱を招くのかはよく分からない
リンク先スレッドの「GIL の削除が Python だけで書かれたコードベースを壊す可能性は非常に低い」という文が本当に正しいのか疑わしい
一部のマルチスレッド Python コードは、GIL のおかげで特定の操作が暗黙にスレッドセーフだと期待している可能性がある。たとえば 2 つのスレッドが同じリストに項目を追加してもリストが壊れないのは、GIL によってその操作を 2 つのスレッドが並列に実行しないためである。GIL を削除すると、C++ で
std::vectorを同時に変更するときのように、こうしたコードが突然罰を受けることになりかねない。確信はないが、この文は少し怪しい。 https://discuss.python.org/t/pep-703-making-the-global-inter...PEP 703 の コンテナのスレッド安全性 の部分はこの問題を扱っている。各 list、dictionary、set に軽量なオブジェクトごとのロックを置き、オブジェクトを変更するすべての操作はそのロックを取得しなければならず、ほとんどの読み取り操作もロックを取得するよう提案している。詳細は https://peps.python.org/pep-0703/#container-thread-safety にある
ただしそうすると、同期されていない
[]が必要なときにどうするかという問題が残るオープンソースでこれより難しい試練は想像しにくい
決定自体は合理的だ。テストモードで前進し、マルチインタプリタは中間的な実験として扱いつつ、目標は同時実行可能な Python に置くというものだ。ただし、既存コードと新しいコードを同じ仮想マシン上で動かすという制約は非常に大きい。LWN の要約がテストをほとんど扱っていない点は驚きだが、テストはまだかなり未解決で、未知ではあるものの深刻なバグを含むリリースにつながる可能性がある。Microsoft、Facebook/Meta、Conda がリソースを出し、コア貢献者の圧倒的多数が前進を望んでいるが、作業が難しくなり、より多くの人が必要になったときにどうなるかは不透明だ。同時に、Web サイトからビッグデータ、AI まで、学術界と産業界の巨大プロジェクトが Python に依存しており、Python 開発者に転嫁されるコストは GDP 比で測定できるかもしれない。まだ問題が明らかになっているようにも見えないので、今後 3 年以上にわたり予測可能な改善を進める Faster CPython のアプローチに集中し、同時実行 Python の支持者は単純なプロトタイプを超えて、どのような問題が起こり得るのか、どう検出するのか、何ができるのかを分析すべきだ。同時性の保証を証明した経験のある人たちがレビューし、未知のものが少なくとも特定された後で運営委員会に質問を上げる方が公平だ。オープンソースにはプログラム管理規模の意思決定は多くなく、Apache、Eclipse、Linux のように市場の方向を動かす比較的単純な決定が多かったが、今回は実際の技術的な未知数がある。同時に 言語間 ABI も扱う必要があると感じる。大きな問題は C が期待する実行モデルと合わせることであり、Java の外部関数・メモリインターフェースは何年もインキュベーション中で、Swift も C と C++ のラッピングが改善されつつあるが、FFI は悪名高く、おそらく不必要に難しくもある
個人的には GIL の削除は間違いだと思う。大きな恩恵を受けるアプリケーションは多くなく、ほとんどは性能ペナルティを受けるだろう
この作業は何年もの関心と労力を食い潰すはずで、もっと賢く使えたのではないかと思う。Python は GIL に対して不安や劣等感を抱いているように見える。むしろ JavaScript のようにシングルスレッドモデルを完全に受け入れる方がよいと思う。一部のアプリケーションは引き続き難しい、あるいは不可能だろうが、高性能や高スケーラビリティが必要なアプリに Python がよい選択肢だとは思わない。ある程度特化していて、すべてのユースケースをサポートしないことが必ずしも悪いわけではない
人々は今、Python で既に行っている作業に性能を必要としている。それが事実ではなかった時代に戻ることはできない。今やそれは Python の最も一般的なユースケースの一つであり、人々はここにキャリアを懸けている
人々はすでに Python で並列作業をしようとしている。別の言語を使えと強制しても、あまり役には立たない
データ集約型の作業のかなりの部分は Python から並列プロセスで簡単に走らせられるので、GIL 削除がそこまで大きな利得なのかはよく分からない
シングルスレッド性能は、資金を多く投入して改善するのがはるかに難しいため、より優先すべき
マルチスレッド性能は、コアを1つ追加することでプロセスベースの並列化のオーバーヘッドを相殺できる。GIL 対 no-GIL という二分法自体が間違っていると思う。multiprocessing における最大の問題はメモリを共有できないこと。したがって、明示的なメモリ共有メカニズムを持つ仮想プロセスを追加すればよい。そうすればオブジェクトは1つのスレッドにとどまるため、バリアなしの参照カウントのようなシングルスレッド最適化を維持できる
GIL がなくてもシングルスレッド性能を高くできる。Rust にはゼロコスト抽象化という概念があり、スレッドもうまく扱える。Java もシングルスレッドの処理をうまくこなす。他にも多くの言語があり、SF の話ではない。ロックは最適化で消せるし、そもそもロックのないコードを選ぶこともでき、細粒度または構造化された並行性も可能だ。何がスレッドセーフかは基本的に API 契約である。楽観的ロックも存在する。Python が同様のことをできない十分な理由はないが、まず GIL を取り除く必要がある。GIL のない Python の性能低下は、多くの部分が未解決の技術的負債に近く、時間とともに修正できる。大量のロックを入れるのは応急処置なので遅くなるが、適切な解決策は内部動作を考え直すか、スレッドセーフかどうかを文書化する API 契約を整えることになる可能性が高い。より高速な Python ランタイムとコンパイラにより、現在ネイティブライブラリに依存している多くのものを Python で再実装できるようにもなる。ネイティブコードとの相互作用こそロックが必要になる箇所が多く、そのやり方を変えなければ問題は続く。GIL 削除の核心は、こうしたものを体系的に見つけて修正することにあり、時間とともに改善していくはずだ
Python/multiprocessing の唯一の問題は、ときにキューではなく共有可変状態が必要になる点だ。現在 Python オブジェクトを共有メモリに置く方法は複雑で制限が多く、非効率である。直すべき目標はそこにあり、Python にはネイティブインスタンスを共有メモリに配置するためのより良いサポートが必要だ
「シングルスレッドコードにどの程度の性能低下が許容できるか」という質問に Shannon は**15〜20%**程度と推定したが、その質問はおおむね答えを得られなかった
つまり「CPython をより速く」しているプロジェクトの一部の人たちは、既存の Python コードの大半を一夜にして15〜20%遅くすることを受け入れられると見ているのか。せいぜい5%程度が限界だと思う。それも GIL 削除が今後の他の最適化に役立つ場合に限られる。ところがむしろ、その変更は他の最適化を複雑にし、遅らせるという。一方 Shannon は2020年に個人として CPython を5倍速くするという資金募集の提案をしており、今でははるかに大きな企業支援を受けるチーム全体が CPython の高速化に取り組んでいるのに、目標はずっと小さく見える
性能が本当に重要なとき、別の言語で書き直さずに20倍程度の高速化が得られるなら、それには大きな意味がある
他の最適化が止まるのではなく、少し時間がかかる程度なら受け入れられるかもしれない
ネットワークやディスクアクセスなしで数値・文字列演算を含む実際のコードを比較すると、3.12 ベータは 3.8 より20〜25%程度しか時間が短くならない。それは 2.7 レベルだ。古参の中心人物たちが、次のリリースで企業スポンサーに見せる bullet point 機能を必死に探しているように見える。だから Sam Gross の作業を使うが、時間が経つにつれて功績はゆっくり彼らが持っていきそうだ
LWN らしい素晴らしい整理だ
Python コミュニティが好きだ。オープンソースソフトウェアの先導的な事例であり、透明性と良いガバナンスが何を成し遂げられるかを示している。Meta、Microsoft などが投入しているエンジニアリング時間には感謝しているが、技術産業全体とデータサイエンスを含むより広い領域が Python とオープンソースソフトウェアから得ている価値に比べれば、依然としてあまりにも小さい
8年前、JPMorgan で技術リーダーシップチームを説得し、PyCon UK のスポンサー、採用ブース、英国全土の JPMorgan ジュニア開発者の参加支援を行わせた。5年前に JPM を離れたが、今でも PyCon UK のヘッドラインスポンサーだ。Python とオープンソースエコシステムから得た莫大な利益に比べれば、まったく無視できるほどの費用だった
メーリングリストは検閲され、内輪のサークルは批判されない。本当の貢献者たちは、正しい企業に属していて大して何もしないのに事務的な権限のある地位を占める人たちに搾取されている。LWN の記事は非常に好意的で、意思決定者の名前をいつもきちんと挙げるので、だまされてはいけない。選択的な報道に近いと思う
Sam Gross が推し進めたやり方はかなり印象的だ。運営委員会から前向きだが確約のない反応を受けたあと、ただ座って進展を待つこともできたのに、反対して圧力をかけた点は大いに評価できる
非常に興味深い。Sam Gross が「今すぐ yes/no が必要なわけではないが、受け入れがどのような形になるのかを知る必要があり、この issue はあまりにも長く放置されていた」と述べたのは、かなり大胆な動きだった: https://github.com/python/steering-council/issues/188#issuec...
あのやり取りはいろいろな方向に進み得たが、運営委員会にまさに必要な刺激だったように思う。no-GIL Python まではまだ長く曲がりくねった道のりで、2桁のエンジニア年規模が必要になるだろうが、少なくともきちんとした道筋はできたように見える。最も難しい部分は、既存コードベースの正確性を保証することだ。Python 2 から 3 への移行を繰り返したくないと言うことと、破壊的変更はないと主張していても、バグへの不安から実際にはアップグレードを避けることは、まったく別の問題だ。GIL/no-GIL をコンパイル時スイッチとしてだけ残すとしても、保守コストは確実に増える。それでも長期的には、この取り組みには価値があると思う。GIL は Python 批判の避雷針のような存在で、Python と並列性に関する HN スレッドを見れば分かる。おそらく、人々が何十年もの文脈を理解しなくても「これが Python が速くなれない理由だ」と直接指させる対象だからだろう。その意味では、チェスタトンの柵のラスボスに近い
新しい指針の下でも、GIL 除去に向けた複数年の取り組みが最終的に拒否される可能性は依然としてある