web-dev-qa-db-ja.com

Java "Virtual Machine" vs. Python "Interpreter"の用語?

Python "virtual machine"を読むのはまれに思えますが、Java "virtual machine"は常に使用されます。

どちらもバイトコードを解釈します。なぜ一方を仮想マシン、もう一方をインタープリターと呼ぶのですか?

189
twils

仮想マシンは、特定の言語に依存せずにサポートされる原子的に明確に定義された特定の命令セットを備えた仮想コンピューティング環境であり、一般にそれ自体がサンドボックスと考えられています。 VMは、特定のCPUの命令セットに類似しており、そのような命令(またはバイトコード)の非常に基本的なビルディングブロックで、次から独立してより基本的なレベルで動作する傾向があります。命令は、仮想マシンの現在の状態のみに基づいて決定論的に実行され、その時点での命令ストリームの他の場所の情報には依存しません。

一方、インタープリターは、特定の言語および特定の文法のストリームを解析するように調整されているため、周囲のトークンのコンテキストでデコードする必要があるため、より高度です。各バイトまたは各行を単独で見て、次に何をすべきかを正確に知ることはできません。言語のトークンは、VMの命令(バイトコード)に関連するように分離して取得することはできません。

JavaコンパイラはJava言語をバイトコードストリームに変換します。CコンパイラがC言語プログラムをアセンブリコードに変換するのと同じです。一方、インタープリターはプログラムを明確に定義された中間形式に変換するのではなく、ソースを解釈するプロセスの問題としてプログラムのアクションを実行するだけです。

VMとインタープリターの違いのもう1つのテストは、それを言語に依存しないと考えるかどうかです。 Java VMとして知っていることは、実際にはJava固有ではありません。 JVMで実行できるバイトコードを生成する他の言語からコンパイラを作成できます。一方、Pythonインタープリターによる解釈のために、Python以外の他の言語をPythonに「コンパイル」することを本当に考えるとは思わない。

解釈プロセスが高度であるため、これは比較的遅いプロセスになる可能性があります....具体的には、言語トークンなどの解析および識別、およびソースのコンテキストを理解して、インタープリター内で実行プロセスを実行できるようにします。このようなインタープリター言語の高速化を支援するために、ここで、事前に解析され、トークン化されたソースコードの中間形式を定義し、より簡単に直接解釈できます。この種のバイナリ形式はまだ実行時に解釈されますが、パフォーマンスを改善するために人間が読めない形式から始めています。ただし、そのフォームを実行するロジックは仮想マシンではありません。これらのコードを分離して使用することはまだできないためです。周囲のトークンのコンテキストは依然として重要であり、現在はコンピューターの効率が異なる別の形式になっています。

126
Tall Jeff

この投稿では、「仮想マシン」とは、QemuやVirtualboxなどのシステム仮想マシンではなく、プロセス仮想マシンを指します。プロセス仮想マシンは、一般的なプログラミング環境を提供する単なるプログラムであり、プログラム可能なプログラムです。

Javaにはインタープリターと仮想マシンがあり、Pythonには仮想マシンとインタープリターがあります。 「仮想マシン」がJavaでより一般的な用語であり、「インタープリター」がPythonでより一般的な用語である理由は、2つの言語の大きな違いに大きく関係しています。 )vs動的型付け(Python)。このコンテキストでは、「タイプ」は プリミティブデータタイプ -データのメモリ内ストレージサイズを示唆するタイプを指します。 Java仮想マシンは簡単です。プログラマーは各変数のプリミティブデータ型を指定する必要があります。これにより、JavaバイトコードがJava仮想マシンによって解釈および実行されるだけでなく、 マシン命令にコンパイルされた であるための十分な情報が提供されます。 Python仮想マシンは、各操作の実行前に一時停止する追加タスクを実行して、操作に含まれる各変数またはデータ構造のプリミティブデータ型を決定するという意味で、より複雑です。 Pythonは、プログラマーがプリミティブデータ型の観点から考えることから解放され、操作をより高いレベルで表現できるようにします。この自由の代価はパフォーマンスです。 「インタープリター」は、データ型を検査するために一時停止する必要があり、また動的に型付けされた言語の比較的簡潔な構文が対話型インターフェースに適しているため、Pythonの優先用語です。インタラクティブなJavaインターフェイスを構築するための技術的な障壁はありませんが、静的に型付けされたコードをインタラクティブに記述しようとすると退屈になります。

Javaの世界では、仮想マシンは実際にマシン命令にコンパイルできる言語で書かれたプログラムを実行するため、ショーを盗み、結果として速度とリソース効率が向上します。 Javaバイトコードは、コンパイルされたプログラムのパフォーマンスに比較的近いパフォーマンスで、Java仮想マシンによって実行できます。これは、バイトコードにプリミティブデータ型情報が存在するためです。 Java仮想マシンは、Javaを独自のカテゴリーに入れます。

静的に型付けされた言語を解釈するポータブル

次に近いものはLLVMですが、LLVMは異なるレベルで動作します:

移植可能な解釈アセンブリ言語

「バイトコード」という用語はJavaとPythonの両方で使用されますが、すべてのバイトコードが同じように作成されるわけではありません。バイトコードは、コンパイラ/インタープリターが使用する中間言語の総称です。 gccのようなCコンパイラでさえ 中間言語(または複数) を使用してジョブを完了します。 Javaバイトコードにはプリミティブデータ型に関する情報が含まれていますが、Pythonバイトコードには含まれていません。この点で、Python(およびBash、Perl、Rubyなど)の仮想マシンは、実際にはJava仮想マシンよりも根本的に遅い、または単にやるべきことが多くあります。さまざまなバイトコード形式に含まれる情報を考慮すると便利です。

  • llvm:CPUレジスタ
  • Java:プリミティブデータ型
  • Python:ユーザー定義型

実世界の類似性を引き出すには:LLVMは原子を使用し、Java仮想マシンは分子を使用し、Python仮想マシンは材料を使用します。最終的にはすべてが原子以下の粒子に分解される必要があるため(実際のマシン操作)、Python仮想マシンには最も複雑なタスクがあります。

静的に型付けされた言語のインタープリター/コンパイラーは、動的に型付けされた言語のインタープリター/コンパイラーと同じ荷物を持っていません。静的に型付けされた言語のプログラマーはスラックを吸収する必要があります。そのため、パフォーマンスが向上します。ただし、すべての非決定的関数が密かに決定的であるように、すべて動的に型付けされた言語も密かに静的に型付けされています。したがって、2つの言語ファミリ間のパフォーマンスの違いは、Pythonがその名前をHAL 9000に変更する頃に、横ばいになるはずです。

Pythonのような動的言語の仮想マシンは、理想的な論理マシンを実装しており、実際の物理ハードウェアと必ずしも厳密に対応しているわけではありません。対照的に、Java仮想マシンは、マシン命令を発行する代わりに組み込みルーチンを実行することを除いて、機能が従来のCコンパイラに似ています。 Pythonでは、整数はPythonオブジェクトであり、一連の属性とメソッドが付加されています。 Javaでは、intは指定されたビット数であり、通常は32です。実際には公平な比較ではありません。 Python整数は、実際にJava整数クラスと比較する必要があります。 Javaの「int」プリミティブデータ型は、Python言語にはプリミティブのこの層がなく、Pythonバイトコードも不足しているため、Python言語の何とも比較できません。

Java変数は明示的に入力されるため、 Jython パフォーマンスのようなものが cPython と同じ球場にあると合理的に期待できます。一方、Javaで実装されたPython仮想マシンは、泥よりも遅いことがほぼ保証されています。そして、Ruby、Perlなどがこれ以上うまくいくと期待しないでください。彼らはそうするように設計されていませんでした。これらは「スクリプティング」のために設計されました。これは、動的言語のプログラミングと呼ばれています。

仮想マシンで行われるすべての操作は、最終的に実際のハードウェアにヒットする必要があります。仮想マシンには、論理演算の任意の組み合わせを実行するのに十分な一般的なプリコンパイル済みルーチンが含まれています。仮想マシンは新しいマシン命令を発行しないかもしれませんが、確かに複雑なシーケンスで何度も何度も独自のルーチンを実行しています。 Java仮想マシン、Python仮想マシン、および他のすべての汎用仮想マシンは、思いつく限りのロジックを実行するように調整できるという意味では同等ですが、どのタスクを引き受けるか、どのタスクをプログラマーに任せるかという点で異なります。

PythonのPsycoは完全なPython仮想マシンではなく、通常のPython仮想マシンを数行のコードをコンパイルできると考えるポイントでハイジャックするジャストインタイムコンパイラーです。 -主に、反復ごとに値が変化しても、変数のプリミティブ型が一定のままであると考えるループ。その場合、通常の仮想マシンの絶え間ないタイプの決定を一部省略できます。ただし、Psycoの足元からタイプを引き抜かないように、少し注意する必要があります。ただし、Pyscoは通常、タイプが変更されないことを完全に確信していない場合、通常の仮想マシンにフォールバックすることを知っています。

この話の教訓は、プリミティブなデータ型情報がコンパイラ/仮想マシンにとって本当に役立つということです。

最後に、すべてを概観するには、これを考慮してください。Pythonインタープリター/仮想マシンで実行されるPythonで実行されるJavaインタープリター/仮想マシンによって実行されるJavaプログラムiPhoneで実行されているqemu仮想マシンで実行されているLLVMで。

パーマリンク

149
Poor Yorick

おそらく異なる用語の1つの理由は、通常pythonインタプリタの生の人間が読めるソースコードを供給し、バイトコードなどを心配しないことを考えていることです。

Javaでは、明示的にバイトコードにコンパイルしてから、VM上のソースコードではなく、バイトコードのみを実行する必要があります。

Pythonはユーザーの観点からすると、隠れた仮想マシンを使用していますが、ほとんどの場合、この詳細を無視できます。

58
Mr Fooz

Interpreter、ソースコードを効率的な中間表現(コード)に変換し、すぐにこれを実行します。

仮想マシン、インタープリターシステムの一部であるコンパイラーによってビルドされた保存済みのプリコンパイル済みコードを明示的に実行します。

仮想マシンの非常に重要な特性は、内部で実行されるソフトウェアが仮想マシンによって提供されるリソースに制限されることです。正確には、仮想世界から抜け出すことはできません。リモートコードの安全な実行を考えてください。Javaアプレット。

Pythonの場合、この投稿のコメントで述べたように、pycファイルを保持している場合、メカニズムはVMのようになり、このバイトコードはより速く実行されます-まだ解釈されますが、コンピューターにやさしい形式です。これを全体として見ると、PVMはPython Interpreter。

つまり、refer Python Interpreterの場合、全体として参照していることを意味します。PVMの場合、Pythonランタイム環境であるインタープリターJavaの場合と同様に、異なるパーツ、異なるJRE、JVM、JDKなどを参照します。

詳細については、Wikipediaエントリ: インタープリター 、および 仮想マシン 。さらにもう1つ ここ 。ここに アプリケーション仮想マシンの比較 があります。コンパイラ、インタープリター、VMの違いを理解するのに役立ちます。

15
Adeel Ansari

用語インタープリターは、以前のシェルスクリプト言語にさかのぼるレガシー用語です。 「スクリプト言語」がフル機能の言語に進化し、対応するプラットフォームがより洗練され、サンドボックス化されるにつれて、仮想マシンとインタープリターの区別(Python意味)は非常に小さいまたは存在しない。

Pythonインタープリターは、別個のコンパイルステップなしで実行できるという意味で、シェルスクリプトと同じように機能します。それ以上に、Pythonのインタープリター(またはPerlまたはRubyの)とJavaの仮想マシンのほとんどは実装の詳細です(JavaはPythonよりも完全にサンドボックス化されていますが、どちらも最終的にはネイティブCインターフェイスを介して基盤となるアーキテクチャへのアクセスを提供します)

12
Daniel Naab

両者の間に実際の違いはありません。人々はクリエイターが選んだ慣例に従うだけです。

9
Cody Brocious

なぜJava仮想マシン、しかしPythonインタープリター?」という質問に対する深い答えを提供するために、出発点としてコンパイル理論の分野に戻りましょう。議論の。

プログラムのコンパイルの一般的なプロセスには、次の手順が含まれます。

  1. 字句解析。プログラムテキストをtokensと呼ばれる意味のある「単語」に分割します(プロセスの一部として、プログラムの動作に影響を与えないため、すべてのコメント、スペース、改行などが削除されます)。結果は、トークンの順序付けられたストリームです。
  2. 構文解析。トークンのストリームから、いわゆるAbstract Syntax Tree(AST)を構築します。 ASTはトークン間の関係を確立し、その結果、プログラムの評価の順序を定義します。
  3. セマンティック分析。型に関する情報とプログラミング言語のセマンティックルールのセットを使用して、ASTのセマンティックな正当性を検証します。 (たとえば、a = b + cは構文の観点からは正しいステートメントですが、aが定数オブジェクトとして宣言されている場合、セマンティックの観点からは完全に不正です)
  4. 中間コード生成。 ASTをマシンに依存しない「プリミティブ」操作の線形に順序付けられたストリームにシリアル化します。実際、コードジェネレーターはASTを走査し、評価ステップの順序を記録します。その結果、プログラムのツリーのような表現から、プログラムの評価の順序が保存されたはるかに単純なリストのような表現を実現します。
  5. マシンコード生成。マシンに依存しない「プリミティブ」バイトコード形式のプログラムは、特定のプロセッサアーキテクチャのマシンコードに変換されます。

OK。ここで用語を定義しましょう。

Interpreterは、そのWordの古典的な意味で、プログラムから直接生成されたASTに基づくプログラム評価に基づいて実行を想定していますtext。その場合、プログラムはソースコードの形式で配布され、インタープリターはプログラムテキストによって、頻繁に動的に(ステートメントごとまたは行ごとに)フィードされます。各入力ステートメントに対して、インタープリターはそのASTをビルドし、プログラムの「状態」を変更してすぐに評価します。これは、スクリプト言語が示す典型的な動作です。たとえば、Bash、Windows CMDなどを検討してください。概念的には、Pythonもこの方法を取ります。

インタープリターの中間マシンに依存しないバイナリバイトコードステップの生成でASTベースの実行ステップを置き換える場合、プログラム実行のプロセス全体をコンパイルと実行の2つの別々のフェーズに分割します。その場合、以前はインタプリタであったものがバイトコードコンパイラになり、プログラムがtextの形式からbinaryの形式に変換されます。その後、プログラムはそのバイナリ形式で配布されますが、ソースコードの形式では配布されません。ユーザーマシンでは、そのバイトコードが新しいエンティティ--仮想マシンに送られ、実際にそのバイトコードが解釈されます。このため、仮想マシンはバイトコードインタープリターと呼ばれます。ただし、ここに注意してください!古典的なインタープリターはテキストインタープリターですが、仮想マシンはバイナリインタープリター!です!これは、JavaとC#が取ったアプローチです。

最後に、バイトコードコンパイラにマシンコード生成を追加すると、結果として古典的なコンパイラと呼ばれる結果が得られます。古典的なコンパイラは、プログラムのソースコードを特定のプロセッサのマシンコードに変換します。そのマシンコードは、追加の調停なしで(テキストインタープリターでもバイナリインタープリターでもないインタープリターなしで)ターゲットプロセッサで直接実行になります。

元の質問に戻って、Java対Pythonについて考えてみましょう。

Javaは当初、実装の依存関係をできるだけ少なくするように設計されました。その設計は、「一度書き込み、どこでも実行」(WORA)の原則に基づいています。それを実装するために、最初にJavaは、マシンに依存しないバイナリバイトコードにコンパイルするプログラミング言語として設計されました。これはJavaをサポートするすべてのプラットフォームで実行できます再コンパイルの必要なし。 JavaはWORAベースのC++と同じように考えることができます。実際、JavaPythonのようなスクリプト言語よりもC++に近いです。しかしC++とは対照的に、Javabinary bytecodeにコンパイルされるように設計されており、virtualの環境で実行されますmachine、一方、C++はマシンコードでコンパイルされ、ターゲットプロセッサによって直接実行されるように設計されています。

Pythonは当初、スクリプトを解釈する一種のスクリプトプログラミング言語として設計されました(プログラミング言語の規則に従って記述されたtextの形式のプログラム)。このため、Pythonは最初に、BashまたはWindows CMDが行うように、1行のコマンドまたはステートメントの動的な解釈をサポートしました。同じ理由で、Pythonの初期実装には、そのようなバイトコードを実行するためのバイトコードコンパイラと仮想マシンはありませんでしたが、最初からPythonが必要でしたインタープリター Pythonプログラムを理解および評価できますテキスト

このため、歴史的に、Java開発者はJava Virtual Machine(最初はJavaJavaバイトコードコンパイラおよびバイトコードインタープリター-[〜#〜] jvm [〜#〜])、およびPythonPythonインタープリターについて(最初はPythonには仮想マシンがなく、一種の古典的なテキストインタープリタープログラムを実行しますテキストあらゆる種類のコンパイルやバイナリコードへの変換なしで直接)。

現在、Pythonの内部には仮想マシンもあり、Pythonバイトコードをコンパイルおよび解釈できます。そして、その事実は、混乱に追加の投資をします。「なぜJava仮想マシン、しかしPythonインタープリター? "。両方の言語の実装には仮想マシンが含まれているようです。しかし!現在でも、プログラムテキストの解釈は、Pythonプログラムの実行の主要な方法です。 Python実装は、最適化手法としてのみ、内部で仮想マシンを活用します。仮想マシンでのバイナリバイトコードの解釈は、元​​のプログラムテキストを直接解釈するよりもはるかに効率的です。同時に、Python内の仮想マシンの存在は、Python言語デザイナーとPythonプログラム開発者の両方にとって完全に透過的です。仮想マシンの有無にかかわらず、同じ言語をインタープリターに実装できます。同様に、仮想マシンの有無にかかわらず、同じプログラムをインタープリターで実行でき、そのプログラムはまったく同じ動作を示し、同じ入力から同じ出力を等しく生成します。唯一の違いは、プログラムの実行速度とインタープリターが消費するメモリ量です。したがって、Pythonの仮想マシンは言語設計の不可避な部分ではなく、主要なPythonインタープリターのオプションの拡張です。

Javaも同様の方法で検討できます。内部のJavaにはJITコンパイラがあり、Javaクラスのメソッドをターゲットプラットフォームのマシンコードに選択的にコンパイルし、直接実行できます。しかし! Javaは、引き続きJavaプログラム実行の主要な方法としてバイトコード解釈を使用します。 Python実装が最適化手法としてのみ内部の仮想マシンを活用するように、Java仮想マシンは最適化の目的でJust-In-Timeコンパイラーのみを使用します。同様に、マシンコードの直接実行がJavaバイトコードの解釈よりも少なくとも10倍速いという事実のためです。 Pythonの場合と同様に、JVMの内部にあるJITコンパイラーの存在は、Java言語デザイナーとJavaプログラム開発者の両方にとって完全に透過的です。同じJavaプログラミング言語は、JITコンパイラの有無にかかわらずJVMで実装できます。また、同じ方法で、同じプログラムを内部のJITの有無にかかわらずJVMで実行できます。同じプログラムはまったく同じ動作を示し、両方のJVM(JITの有無にかかわらず)で同じ入力から同じ出力を等しく生成しますPythonの場合と同様に、両者の唯一の違いは、実行速度とJVMが消費するメモリ量にあります。最後に、Pythonの場合のように、JavaのJITも言語設計の避けられない部分ではなく、主要なJVM実装のオプションの拡張です。

JavaとPythonの仮想マシンの設計と実装の観点からは、両者は大きく異なりますが、どちらも(注意!)仮想マシンのままです。 JVMは、単純な基本操作と高い命令ディスパッチコストを備えた低レベルの仮想マシンの例です。 Pythonは高レベルの仮想マシンであり、そのための命令は複雑な動作を示し、命令のディスパッチコストはそれほど大きくありません。 Javaは非常に低い抽象化レベルで動作します。 JVMは、明確に定義された小さなプリミティブ型のセットで動作し、バイトコード命令とネイティブマシンコード命令の間には非常に厳密な対応(通常1対1)があります。それどころか、Python仮想マシンは高い抽象化レベルで動作し、複雑なデータ型(オブジェクト)で動作し、アドホックポリモーフィズムをサポートします。一方、バイトコード命令は、一連の複数のネイティブマシンコードの指示。たとえば、Pythonは無制限の範囲数学をサポートしています。したがって、Python VMは、演算の結果がマシンのWordをオーバーフローさせる可能性のある潜在的に大きな整数の長い算術演算を利用せざるを得ません。したがって、Pythonの算術演算用の1バイトコード命令はPython VM内の関数呼び出しに公開できますが、JVM算術演算では1つまたは少数のネイティブマシン命令で表される単純な演算に公開されます。

その結果、次の結論を導き出すことができます。 Java仮想マシンですが、Pythonインタープリターは次の理由によります。

  1. 仮想マシンの用語はバイナリバイトコードの解釈を前提とし、用語インタープリターはプログラムのテキストの解釈を前提としています。
  2. 歴史的に、Javaはバイナリバイトコード解釈用に設計および実装され、Pythonは最初にプログラムテキスト解釈用に設計および実装されました。したがって、「Java Virtual Machine」という用語は歴史的であり、Javaコミュニティで確立されています。同様に、「Pythonインタープリター」という用語は歴史的であり、Pythonコミュニティで確立されています。人々は伝統を長引かせ、ずっと前に使用されたのと同じ用語を使用する傾向があります。
  3. 最後に、現在、Javaの場合、バイナリバイトコードの解釈がプログラム実行の主要な方法ですが、JITコンパイルはオプションの透過的な最適化です。 Pythonでは、現在、プログラムテキストの解釈はPythonプログラムの実行の主要な方法ですが、Python VMバイトコードへのコンパイルはオプションで透過的な最適化です。

そのため、JavaとPythonの両方の仮想マシンはバイナリバイトコードインタープリターであり、「なぜJava仮想マシンが、Pythonインタープリター? "。ここで重要な点は、Pythonの場合、仮想マシンはプログラム実行の主要な手段または必要な手段ではないということです。これは、従来のテキストインタープリターのオプションの拡張機能です。一方、仮想マシンは、Javaプログラム実行エコシステムのコアであり、避けられない部分です。プログラミング言語設計の静的または動的タイピングの選択は、主に仮想マシンの抽象化レベルのみに影響しますが、仮想マシンが必要かどうかを決定するものではありません。両方のタイピングシステムを使用する言語は、目的の実行モデルに応じて、仮想マシンの環境内でコンパイル、解釈、または実行されるように設計できます。

6
ZarathustrA

Pythonにはx86用のJITコンパイラーがあり、問題をさらに混乱させていることを忘れないでください。psycoを参照してください。

「解釈された言語」のより厳密な解釈は、たとえばPythonと比較してVMのパフォーマンスの問題について議論する場合にのみ有用になります。Rubyは、 Pythonとは異なり、インタープリター言語-言い換えれば、コンテキストがすべてです。

3
Arafangion

いいえ、両方ともバイトコードを解釈しません。

Pythonは、pypyで実行している場合にのみバイトコードを解釈します。それ以外の場合は、Cにコンパイルされ、そのレベルで解釈されます。

Javaはバイトコードにコンパイルされます。

0

まず、プログラミングやコンピューターサイエンス全般は数学ではなく、頻繁に使用するほとんどの用語の厳密な定義がないことを理解する必要があります。

あなたの質問に今:

通訳とは(コンピューターサイエンス)

ソースコードを最小の実行可能ユニットで変換してから、そのユニットを実行します。

仮想マシンとは

jVMの場合、仮想マシンは、インタープリター、クラスローダー、ガベージコレクター、スレッドスケジューラー、JITコンパイラー、その他多くのものを含むソフトウェアです。

ご覧のとおり、インタープリターは一部またはJVMであり、JVMには他の多くのコンポーネントが含まれているため、JVM全体をインタープリターと呼ぶことはできません。

Pythonについて話すときにWordの「インタープリター」を使用する理由

Javaを使用すると、コンパイル部分が明示的になります。一方、pythonは、そのコンパイルと解釈プロセスについてJavaのように明示的ではありません。エンドユーザーの観点から、解釈はpythonプログラムの実行に使用される唯一のメカニズムです。

0
mightyWOZ