たとえば、C#、Java、または C++ がすべてマシン コードにコンパイルされる場合、パフォーマンスが同等ではないのはなぜでしょうか?
私の理解では、そのような言語は機械語の抽象化であり、最終的には機械語にコンパイルされます。プロセッサがパフォーマンスを決定するべきではありませんか?
たとえば、C#、Java、または C++ がすべてマシン コードにコンパイルされる場合、パフォーマンスが同等ではないのはなぜでしょうか?
私の理解では、そのような言語は機械語の抽象化であり、最終的には機械語にコンパイルされます。プロセッサがパフォーマンスを決定するべきではありませんか?
1 つには、C++ オプティマイザははるかに成熟しています。もう 1 つの理由として、パフォーマンスは常に C++ 言語設計者の包括的な目標でした (「使用しないものにはお金を払わない」というマントラがありますが、これは Java のすべてのメソッドが仮想であるというポリシーについては明らかに言えません) )。
さらに、C++ テンプレートは、Java や C# ジェネリックよりもはるかに最適化に適しています。JIT は、モジュールの境界を越えて最適化する能力を称賛されることがよくありますが、ジェネリックはこれを完全に阻止します。CLR (.NET ランタイム) は、すべての参照型をカバーするジェネリックに対して 1 つのバージョンのマシン コードのみを生成します。一方、C++ オプティマイザーは、テンプレート パラメーターの組み合わせごとに実行され、依存呼び出しをインライン化できます。
次に、C# と Java では、メモリ レイアウトをほとんど制御できません。並列アルゴリズムは、キャッシュ ラインの誤った共有によってパフォーマンスが桁違いに低下する可能性があり、開発者がそれに対してできることはほとんどありません。OTOH C++ は、RAM ページとキャッシュ境界に相対的な特定のオフセットにオブジェクトを配置するツールを提供します。
言語の違いとこれが発生するオーバーヘッドを考慮してください。そのような追加の作業が「同じ効率で」行われたとしても、やるべきことはまだまだあります。限目。(これは、抽象化に伴うことが多い価格です。実行時間の[中程度の]増加に対して、開発時間は[実質的に]短縮できます。)
一方、階乗を計算するループなどの「言語機能」を使用しない自明な関数を使用すると、特定の場合に数値が非常に競合する可能性があります。これは、コンピューター言語ベンチマークゲームで見ることができます(たとえば、 Java7とC ++です)。
言語の実装(JITを含む)と適用される最適化( "-Ox")も主要な要因であることに注意してください。(言語自体は間違いなく「速度がありません」。)
ハッピーコーディング。
been Voigtが指摘したように、JIT/AOTモデルはさまざまな側面に最適化されています。(太陽Oracle Javaの実装には、それぞれが異なるユースケースを優先する個別のサーバーVMとクライアントVMもあります。)JITとAOTについて説明しているSOの投稿を次に示します。
「たとえば、C#、Java、またはC ++がすべて最終的にマシンコードにコンパイルされる場合、なぜそれらは同等のパフォーマンスを発揮しないのですか?」
C#とJavaはどちらもバイトコードにコンパイルされ、最終的には仮想マシンによってマシンコードに変換されます(たとえば、Javaの場合はJVMと呼ばれます)。ただし、C ++は通常、最初はアセンブリレベルまでコンパイルされます。
仮想マシンは実際に実行時に特定の最適化を実行できますが(1つの一般的な例はバイモーフィックインライン化です)、その他の場合、追加されたオーバーヘッドはパフォーマンスに悪影響を及ぼします
同じ C++ コードが、異なるコンパイラまたは同じコンパイラの異なるバージョンで同じマシン コードを生成しないことをご存知ですか? 一部のコンパイラは、同じソースを使用して、別のコンパイラよりも大幅に高速な同じターゲット用のバイナリを作成します。同じ理由で、機械語にコンパイルされる他の言語は同じようには機能しません。一部の言語は、他の言語よりもコンパイル/最適化が容易です。Java のような言語は、機械語コードにコンパイルされないため比較できません。通常、システムに依存しないバイトコードにコンパイルされてから、仮想マシンである jvm で実行されます。jvmは、選択したコードとコンパイラに応じて、高速または低速になるコンパイラによってコンパイルされた言語のコードです。Java (バイトコード) のようなインタープリター言語は、機械語に直接コンパイルされる場合に比べて低速です。
コンパイルしたバイナリを逆アセンブルする方法を学ぶために少し時間をかけてください。java、python などの背後にあるバイトコード タイプの命令セットについて調べます。パスカルが使用していた p コードなど。
x86 コンピューターについて話している場合、そのファミリー間で大きなパフォーマンスの違いがあります。ある x86 プロセッサではクロック レートに比べて非常に高速に実行されるバイナリをコンパイルできますが、別のプロセッサでは同じバイナリの実行が非常に遅くなります。通常、クロック レートが高速な新しいプロセッサは、古いバイナリの実行速度が遅くなります。x86 の世界では、どこでも高速に実行される単一のバイナリを作成するのは無駄な作業です。そのため、パフォーマンスが必要な場合、コンパイラは、システム/プロセッサごとのパフォーマンスを目標にしようとするために、かなりの労力を費やす必要があります。
あなたの質問は、すべての車両が基本的にエンジンと 4 つの車輪を備えている場合、一部の車両がより速く走れるのはなぜかという質問に似ています。なぜある人は他の人よりも多くのものを運べるのですか?
たとえば、C#、Java、または C++ がいずれも最終的にマシン コードにコンパイルされる場合、パフォーマンスが同等ではないのはなぜでしょうか?
最も簡単に言えば、すべてが同じマシンコードにコンパイルされるわけではありません。
少し異なる点として、ウェブ上で見られるパフォーマンスに関する主張の多くは間違っていること、そしてウェブ上で見られるパフォーマンスの測定値の多くは時代遅れであるか信頼できないものであることを理解してください。または他の方法で壊れています。
たとえば、フレネルは小さな乗算プログラムの測定値を指摘し、それらの測定値は次のとおりです。
2003 年に Java 1.4 で作成されました - 現在のバージョンは Java 7 です
非常に単純な方法で作成され、Java がコンパイルを完了できなかった
JVM を再起動せずに彼のプログラムを 6 回実行して、何が起こるか見てみましょう。
public class mult {
public static void main(String[] args){
for (int i=0; i<6; ++i) mult.program_main(args);
}
public static void program_main(String[] args) {
long nbStep = 1000000000;
long tCPU = System.currentTimeMillis();
double t=1. , r= 0.9999999999999999999999999999999999;
if ( args.length > 0 ) {
nbStep = Integer.parseInt(args[0]);
System.out.println( args[0] + " demandees" );
}
for ( long i = 0; i < nbStep; i++ ) {
t = t * r;
}
tCPU = - tCPU + System.currentTimeMillis();
System.out.println(nbStep + " multiplications en " +
tCPU + " millisecondes ." );
}
}
$ /usr/local/src/jdk1.7.0/bin/java -XX:+PrintCompilation -XX:+PrintGC mult
53 1 % mult::program_main @ 57 (122 bytes)
4662 1 % mult::program_main @ -2 (122 bytes) made not entrant
1000000000 multiplications en 4609 millisecondes .
4662 1 mult::program_main (122 bytes)
4669 2 % mult::program_main @ 57 (122 bytes)
1000000000 multiplications en 4612 millisecondes .
1000000000 multiplications en 564 millisecondes .
1000000000 multiplications en 563 millisecondes .
1000000000 multiplications en 563 millisecondes .
1000000000 multiplications en 563 millisecondes .
Java のコンパイルが完了すると、時間は 4609 ミリ秒から 563 ミリ秒に短縮されます。
Java コードは、単純な測定で信じられているよりも8 倍高速です。