私は普段、業務でPythonを使用していますが、最近趣味でRustにも触れています。
今回はRustとPythonでコンパイルについてです。
コンパイルって何よ
コンパイルとは、開発者が書いたプログラミング言語をバイナリ形式(2進法)のデータに変換することです。
普段Pythonを使っているとコンパイルをする機会はあまりないと思います。
Pythonでは
コードを書く→実行
とすぐにコードを実行することができます。
Rustでは
コードを書く→コンパイルする→実行する
という流れになります。
最近はRustでWEBサーバーを作って遊んでいたりしますが、毎回コンパイルしないと変更を確認できないです。
その辺は開発大変がPythonの方が楽かもしれません。
保存すればその変更がすぐに反映されます。
また、JupyerNoteBookのようなセル型で逐次処理するようなこともできるのでデータ分析などはやりやすいと思います。
コンパイルするメリット
開発中に変更を確認するために、毎回コンパイルするのは面倒だなーなんて思っていましたが、コンパイルするとそれなりのメリットもありわけです。
高いパフォーマンス
コンパイルされたコードはネイティブバイナリとなるため、実行時の速度が非常に速くなります。この辺がRustが速い要因でしょう。
厳格なエラーチェック
コンパイル時に型エラーや未使用変数、未初期化の値など、多くの問題を検出してくれます。そもそもエラーになる可能性を確認してくれるので、変更してコンパイルしたらコンパイルエラーになることをたくさんあります。
Pythonだとこの経験がないので、コンパイルエラーになると意外と精神的ダメージがあります。逆にコンパイル時に色々確認してくれるので、実行時にエラーが発生することが少ないです。
メモリ安全性の保証
これはコンパイルしているからなのか、Rustの特性なのか微妙なところですが、コンパイルすることによるメリットなのだと思います。所有権の仕組みと連動して、メモリ安全らしいです。
スレッド安全性
コンパイラがスレッド間でのデータ競合を防ぐため、並列プログラムの安全性が向上するそうです。Pythonの並列処理とかでスレッド間での競合を経験したことがないので、これからメリットを感じられるといいなと思います。
デプロイの効率化
コンパイル済みの単一バイナリは、コンテナやサーバーへのデプロイが簡単になるそうです。環境依存とかが減るということだと思います。
まだデプロイまでやっていないので、デプロイが簡単になるなら楽しみです。
Pythonはどう動いている?
Pythonで書かれたコードはコンパイルせずにどうコンピュータが実行しているのかという疑問が浮かびます。
これはPythonが実行されるときに、1行ずつコンパイルされ処理しています。
厳密にはPythonを実行すると、バイトコード(中間形式)に変換され、このバイトコードを仮想マシンが逐次解釈(1行ずつコンパイルする)して実行されています。
pythonのコードをバイトコード(中間形式)に変換した結果が.pyc
というファイルになります。
Pythonでコードを実行していると、毎回この拡張子のファイルが作られるので何かなと疑問に感じていましたが、Pythonを実行するために必要なファイルだったようです。
完全にコンパイルするPython
Pythonでもコンパイルをすることがあります。
私の知っている範囲では下記2つがあります。
PyInstaller
Pythonの標準で入っている、Pythonスクリプトはスタンドアローンで実行するためのファイルを作成するための機能です。
.exe
ファイルを出力し、Python環境のないPCでもPythonスクリプトを実行できるようになります。
デスクトップ用のアプリケーションなどを配布する際に私は使ったことがあります。
使っている当時はコンパイルしているなんて意識はありませんでした。
Cython
PythonコードをC言語に変換し、コンパイルして実行可能ファイルを生成します。処理速度の向上やソースコードの難読化ができるそうです。
以前は気になっていましたが、今はRustを勉強してしまっているので実際に触ったことがありません。
インタープリター言語 VS コンパイル言語
開発体験
観点 | インタープリター言語 | コンパイル言語 |
---|---|---|
即時性 | ソースコードをそのまま実行可能。変更後すぐに結果を確認できるため、開発サイクルが短い。 | コンパイルが必要なため、変更後に結果を見るまでにやや時間がかかる。 |
エラーチェック | 実行時にエラーが検出される。特に大規模なプログラムでは、実行中のエラー対応に時間がかかる。 | コンパイル時にほとんどのエラーが検出されるため、実行中の予期せぬエラーが少ない。 |
柔軟性 | 動的型付けやランタイムでのコード変更が可能で、柔軟な開発ができる。 | 静的型付けで型の厳格な管理が必要。柔軟性は低いが、コードの安全性が高い。 |
デバッグのしやすさ | 実行時にコードを変更・再実行しやすい。 | エラーが事前に検出されるため、複雑なバグが少なくデバッグ負担が軽減される。 |
開発の習得コスト | 簡単に始められる(例: Pythonは初学者に優しい)。 | 所有権や型システムなど学習が必要な要素が多く、習得に時間がかかる(例: Rust)。 |
開発ツールの活用 | ランタイム環境があれば動作するため、軽量なエディタでも十分。 | IDEや静的解析ツールを活用することで効率的に開発可能。 |
適用シナリオ | プロトタイピングやスクリプト開発、データ解析に適している。 | 高速性や安全性が求められるシステム、ミッションクリティカルなアプリケーションに適している。 |
処理性能
観点 | インタープリター言語 | コンパイル言語 |
---|---|---|
実行速度 | ランタイムで逐次解釈するため比較的遅い。特に計算量が多い処理ではパフォーマンスが低下する。 | コンパイル時に最適化され、機械語で直接実行されるため非常に高速。 |
最適化 | インタープリターで動作するため、最適化が限定的。 | コンパイラがコードを解析し、様々な最適化を適用することで効率的なバイナリを生成。 |
リソース管理 | ガベージコレクションなどに依存するため、リソース消費が予測しづらい場合がある。 | 所有権やライフタイム管理により、効率的かつ安全にリソースを利用できる(例: Rust)。 |
スレッド性能 | スレッド間の安全性を手動で管理する必要があり、データ競合が起こりやすい。 | コンパイラがスレッド安全性を保証するため、並列処理で高い信頼性を発揮する。 |
スケーラビリティ | パフォーマンスの限界が比較的早く訪れるが、小規模なプロジェクトでは問題ない。 | 大規模プロジェクトや高負荷アプリケーションでも優れたスケーラビリティを持つ。 |
個人的にはインタープリター言語の方が学習が楽しいと思います。
学習コストが低いですし、作ってい楽しいです。
インタープリター言語でプログラミングに入門して、処理能力などが必要になったらコンパイル言語を学べばいいのかなと思います。