コンパイラとインタプリタ — 先に全部訳すか、その場で訳すか
私たちが書くソースコードは、そのままではCPUに通じません。人間語を機械語に翻訳する必要があります。その翻訳のやり方が2通りある——これがコンパイラとインタプリタの違いです。
コンパイラは「実行する前に、全部まとめて翻訳してしまう」通訳。最初に時間はかかりますが、できあがった機械語はそのまま何度でも高速に動きます。インタプリタは「1行ずつ、その場で訳しながら実行する」同時通訳。すぐ動き出せますが、同じ行を繰り返すたびに訳し直します。どちらが速いかは「何回くりかえすか」で逆転します。下の図1で確かめましょう。
// あいさつを N 回くりかえす
for (i = 0; i < N; i++) {
print("Hello, world")
} 少ない回数ならインタプリタ、多いならコンパイラ
図1のスライダーを動かすと、はっきり逆転が起きます。N が小さいうちは、コンパイラの「まず全部翻訳する」待ち時間が重く、すぐ走り出せるインタプリタが先にゴールします。ところが N が増えると、インタプリタは同じ行を毎回訳し直すため再翻訳コストが積み上がり、一度翻訳すれば速いコンパイラが追い抜きます。
だから用途で住み分けます。試行錯誤しながら少し動かすスクリプトはインタプリタが快適、何度も繰り返す重い処理はコンパイラ向き。そして現代の多くの言語(JavaScript や Java など)は、いいとこ取りをする JIT(実行時コンパイル)を使います。最初はインタプリタですぐ動き出し、何度も通る「熱い」部分だけを途中で機械語にコンパイルして速くする——起動の速さと実行の速さを両立させる作戦です。
- コンパイラ
- 実行前にソース全体を機械語へ翻訳する方式。起動は遅いが、繰り返し実行は速い。
- インタプリタ
- 1行ずつその場で訳しながら実行する方式。すぐ動くが、繰り返すたび訳し直す。
- JIT
- 実行時コンパイル。まず解釈で動かし、よく通る部分だけ機械語に変えて高速化する。
- 機械語
- CPUが直接実行できる命令。人間語のソースを翻訳した最終形。
まとめ
コンパイラとインタプリタの違いは、「先に全部訳すか、その場で訳すか」の一点に尽きます。図1で見たとおり、起動はインタプリタが速く、繰り返すほどコンパイラが速い——どちらが優れているかではなく、回数しだいで最適が入れ替わるのです。その両取りを狙うのがJIT。コードがどう動いているかの裏側には、こんな翻訳の駆け引きが隠れています。