概要
プログラミング言語には処理速度が速い言語と遅い言語があります。
この記事では処理速度に差が出る理由について解説しています。
背景
自分は過去に9か月ほどAtCoderをやっていた時期があります。
その時はPyPyでコードを書いていました。
もともとPythonで勝負しようとしていたのですが、実行速度が極端に遅くTimeoutを連発していたためです。
で、これまたよくわかってなかったのですが、どうやらPyPy使うと速くできるということを聞いてPyPyに切り替えました。
また、そのとき同時に知ったのはPyPy ←→ Python間だけでなく、プログラミング言語全般において言語よって実行速度に大きく差があるということでした。例えばPyPyで書くとタイムアウトになってしまうようなアルゴリズムでも、C++であればゴリ押しできてしまうことがあるほどです。
はい、そして自分はこのように言語によって速度に差が出る理由について、ろくに勉強せずに何年も過ごしてしまいました。
さすがに恥ずかしくなったのでこの度勉強することにしました。
記事の目的
自分と同じように言語間で速度に差がある理由をモヤモヤにしたままの人はきっといるはずです。
この記事を読んでモヤを晴らしていただくことをこの記事の目的としています。
プログラミング言語の実行速度とコンパイルプロセスの比較
プログラミング言語の実行速度は、ソースコードがどのように機械語(すなわち、実際の計算処理を担うCPUが理解可能なフォーマット)に変換され、実行されるかによって大きく異なります。
実行速度に影響を与える要因
- タイミング:プログラムの機械語への変換が行われるタイミングには、事前と実行時の2つがあります。もちろん、事前に変換されている方が、実行時に変換のためのオーバーヘッドを喰わずにすむので速くなります。
- 単位:変換が行われる単位も重要です。一括で変換する場合と、命令単位や関数単位で逐次的に変換する場合があります。変換単位が細かくなるほど、変換処理の回数が増えることになり、すなわち変換処理のオーバーヘッドを喰いやすくなります。
- 最適化:各言語が実行時に行う最適化の程度も実行速度に影響します。高度な最適化が行われると、実行速度が向上します。
各言語のコンパイルプロセスと実行速度の比較
以下に、主要なプログラミング言語のコンパイルプロセスと実行速度を示したスライドをご紹介します。
上記のスライドについていくつか補足説明を添えます。
中間言語について
中間言語(Intermediate Language)とは、ソースコードと機械語(CPUが理解する命令)の中間段階で使用される言語です。プログラミング言語の実行において、中間言語を使用することにはいくつかのメリットがあります。
中間言語のメリット
- 全体的な労力を減らす:
- 一貫性の確保:中間言語を使用することで、プログラムの中間段階が統一され、各プラットフォームでの動作が一貫します。開発者は、一つの共通フォーマットに対して最適化を行えばよいので、異なるプラットフォームごとの調整作業が大幅に削減されます。
- 再利用性:同じ中間言語を使用する複数の言語(例:JavaとScala)は、同じ仮想マシン(VM)上で動作できます。これにより、VMの開発や最適化の労力が分散され、効率的になります。
- 専門性の分離:
- 言語設計とVM開発の分離:言語設計者は、言語の文法や構文、標準ライブラリの設計に集中できます。一方、VM開発者は、中間言語をいかに効率よく実行するかに専念できます。この分業により、それぞれの専門分野に特化した開発が可能となり、全体の品質と効率が向上します。
中間言語の具体例
- Javaバイトコード:JavaプログラムはまずJavaコンパイラによってJavaバイトコードという中間言語に変換されます。このバイトコードはJVM(Java仮想マシン)上で実行され、各プラットフォームに合わせて最適化されます。
- .NETのCIL(Common Intermediate Language):C#やVB.NETなどの言語は、.NETコンパイラによってCILにコンパイルされ、共通言語ランタイム(CLR)で実行されます。
最適化について
最適化は、プログラムの実行速度やメモリ使用量を改善するために行われるプロセスです。特に競技プログラミングのような環境では、ホットスポットの最適化が実行速度に大きな影響を与えます。
ホットスポットの最適化は、プログラムの中で頻繁に実行される部分(ループや再帰的な関数呼び出しなど)を特定し、機械語のキャッシングを行ったり、その他のポイントで重点的に最適化することを言います。これにより、全体のパフォーマンスが大幅に向上します。