Pythonのマルチスレッドプログラムは、本当の意味で並列には実行されない。代わりに、「並列処理が行われている」という錯覚を生み出す。Pythonの過去の間違いに対処しようと試みる、互換性のないさまざまなPython風ライブラリの作成に、数千時間と数百万ドルが費やされてきた。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
プログラミング言語の設計者が「Python」を設計した当時、コンピュータに複数のコアが搭載されることなど想像できなかった。
1980年代から1990年代にかけて、ソフトウェアエンジニアはムーアの法則に大きな信頼を寄せていた。「集積回路上のトランジスタの数は2年ごとに倍増する」というのがムーアの法則だ。そうなれば、当然速度も同じように速くなる。
このムーアの法則が論理通りに帰結すると、比較的短期間でCPUの速度は事実上無限になる。
Pythonの生みの親として知られるグイド・ヴァンロッサム氏も、このムーアの法則に基づいて、「将来コンピュータには安価で限界なく高速なCPUが1基だけ搭載される」という、致命的欠陥がある想定の下、Pythonの全てのマルチスレッド機能を設計した。
Pythonのグローバルインタープリタロック(GIL:Global Interpreter Lock)は、「全ての操作が単一のコア上で実行される」と想定して構築されている。PC、スマートフォン、マイクロデバイスが複数のCPUを搭載することなど全く想定していなかった。
当然ながら、コンピュータのハードウェアは、CPUの速度をどんどん上げていく方向に向かわなかった。チップの設計者は、CPUの速度を上げるのではなく、CPUを小型化し、チップ上に複数のコアを組み込む方向に進んだ。
ヴァンロッサム氏はレックス・フリードマン氏のポッドキャストで次のように述べている。
「『物事を並列に実行しろ』というプレッシャーが突然降りかかった。Pythonのソリューションではそれは機能しなかった。その瞬間にGILの悪名が広がった」
そのため、Pythonが生まれてから30年以上たった今、256コアを備えるエンタープライズサーバ上でPythonのマルチスレッドアプリを実行しても、255のコアはアイドル状態のままになる。
Pythonでは複数のコアにスレッドを分けることができない。
Pythonアプリではマルチスレッド処理が可能だ。だが、複数のスレッドを複数のコアで実行することはできない。システム内にコアが複数あっても、全ての処理は単独のCPUで行われる。
Pythonは、同時実行と並列実行の概念に極めて独特のアプローチを取っている。
Pythonのマルチスレッドプログラムは、本当の意味で並列には実行されない。代わりに、「並列処理が行われている」という錯覚を生み出す。
Pythonでは「並列処理が行われている」と見えるように、1つのスレッドをCPUで数サイクル実行するようにスケジュールを設定し、数サイクルを終えたらそのスレッドの実行を中断し、別のスレッドを数サイクル実行する。
Pythonの複数のスレッドは、単一CPU上でスケジューリング可能な全スロットに振り分けられる。プロセッサが十分に高速なら、全てがシリアルに実行されていても、複数のプロセスが並列に実行されている感覚になる。
ヴァンロッサム氏は、Pythonのマルチスレッド処理ライブラリ作成時に組み込んだロジックの考え方を次のように述べている。「スレッドのように見えるものを用意した。当時のPCの大半がそうだったようにPC上にCPUが1つしかない限り、スレッドが複数実行されているように感じられる」
Pythonはマルチスレッド処理をサポートする。だが、スレッドは全て同じCPUでシリアルに実行される。並列処理は行われない。全てのPythonアプリケーションはCPUに結び付けられる。
スレッドを複数のコアで実行できないことは、GILの考案時にプラットフォームに永続的に組み込まれたPythonプラットフォームアーキテクチャ上の根本的欠陥だ。
多くの開発者が30年にわたってGILの修正に取り組んできたが、無駄に終わった。
Python 2とPython 3の間で起きた当惑すべき下位互換性の中断でさえ、この問題に対処するには十分ではなかった。このPythonの根本的欠陥は解決できないかもしれない。
「Java」や「C#」のような近代プログラミング言語の設計者は、将来はマルチコアハードウェアになることを当初から理解していた。
Java言語の設計者は1996年の正式リリースよりもはるか前の設計当初から、プログラムのスレッドを無数のコアに分割できるようにAPIを用意していた。Pythonの発案者が想像もしなかったことが、「Java仮想マシン」の中心概念の一つとして設計されている。
近代プログラミング言語は全て、複数コアへのスレッド分割をサポートしている。だが、Pythonは恐らく今後もそうはならないだろう。
GILの欠陥とPythonのマルチスレッド処理の幻覚にPython開発者が対処する方法はあるのだろうか。できることはあまりない。
Pythonの過去の間違いに対処しようと試みる、互換性のないさまざまなPython風ライブラリの作成に、数千時間と数百万ドルが費やされてきた。
こうして膨大な時間と費用をかけた取り組みによって、Pythonの世界には大きな断片化が生まれた。その結果、運用環境に導入されるPythonアプリケーションや、言語モデルの実行に使われるPythonアプリケーションの多くが、 Pythonの標準インストールでは機能しなくなっているのが実情だ。
こうした断片化がPythonコミュニティーに存続の危機をもたらしている。結局のところ、誰かが書いたPythonコードと他の誰かが書いたPythonコードと互換性がなく、標準のPythonプラットフォームで実行できないコードが存在するとしたら、こうした互換性のないコードを本当に「Python」と呼べるのだろうか。
複数のスレッドを複数のコアで実行できるようにGILを置き換えるプロジェクトも幾つか存在する。だが、こうしたプロジェクトでシングルスレッドのPythonアプリケーションを実行すると、速度が遅くなる。Pythonアプリケーションの実行速度が、同じようにコーディングしたJavaアプリケーションの実行速度よりも500〜1000%遅くなるとしたら、これは大きな問題だ。
Pythonでは、最近「PEP 703」が提案されている。これはPythonの将来のリリースではGILをオプションにするという提案だ。だが、広く使われているサードパーティー製ライブラリとPythonとの互換性を著しく損なうことなく実装できるかどうかは不透明だ。
標準GILを対象に作成されたライブラリがマルチスレッドシステムに統合された場合、うまく動く可能性は低い。「C」言語で記述された「CPython」からGILを除去すると、既に大きく断片化している状況にさらなる断片化をもたらす可能性がある。
互換性のない新たなバリエーションやPythonの紛らわしいシリーズの急増によって引き起こされる断片化に終止符を打つ最新の試みの一つが「Mojo」という名前のPythonの新たなバリエーションだ。
プロジェクトMojoはPythonコミュニティーの中で最も優秀な数人が陣頭指揮を執るプロジェクトで、Pythonのスーパーセットだ。
Microsoftが、「JavaScript」の多くの欠陥を修正するために「TypeScript」を作成したのと同様に、MojoもPythonに対して同じことを成し遂げたいと考えられている。
この有望な新規プロジェクトには、次のことが期待されている。
Pythonの問題点を解決するのは気が遠くなるような作業だ。プロジェクトが成功するかどうかは誰にも分からない。だが、全てが計画通り順調に進めば、Pythonの開発者は2026年までにプロジェクトMojoによって、1998年に「JDK」がリリースされたときにJava開発者が手にした全ての特徴、機能、ランタイムパフォーマンスを手に入れるだろう。
「厳密な型指定機能やマルチコアのマルチスレッド機能のサポートを、2026年まで待つことはできない」と考えるPython開発者には他の選択肢もある。
Pythonの長所の一つは、より新しく、より近代的なプログラミング言語で作成されたコードを呼び出す能力にある。
Pythonで記述されたビッグデータサイエンスライブラリの大半は単なる簡易ラッパーで、その内部では「Julia」やC言語のような他の言語が呼び出されている。実際の仕事を行っているのは呼び出される他の言語だ。
Pythonプログラム内で真のマルチスレッド処理機能を必要とするソフトウェアエンジニアは、面倒な作業の際に、マルチスレッドアプリケーションをJavaで作成し、そのJavaコードをPythonコードから呼び出すことができる。
あるいは、最初からJavaでプログラムを作成しても構わない。これにより、頭の痛い数多くの問題を解決できるかもしれない。
Copyright © ITmedia, Inc. All Rights Reserved.