プログラムが2つの異なる言語で記述されているとします。それらを言語Xと言語Yとします。コンパイラーが同じバイトコードを生成する場合、なぜ言語Yの代わりに言語Xを使用する必要がありますか?1つの言語が他の言語よりも高速であることを定義するものは何ですか?
「Cが最も速い言語であり、ATSはCと同じくらい速い言語である」というようなことを人々がよく目にするので、これを尋ねます。プログラミング言語の「高速」の定義を理解しようとしていました。
プログラムが2つの異なる言語で記述されているとします。それらを言語Xと言語Yとします。コンパイラーが同じバイトコードを生成する場合、なぜ言語Yの代わりに言語Xを使用する必要がありますか?1つの言語が他の言語よりも高速であることを定義するものは何ですか?
「Cが最も速い言語であり、ATSはCと同じくらい速い言語である」というようなことを人々がよく目にするので、これを尋ねます。プログラミング言語の「高速」の定義を理解しようとしていました。
回答:
プログラムの読みやすさ、プログラミングの容易さ、多くのプラットフォームへの移植性、優れたプログラミング環境の存在などが、言語Yよりも言語Xを選択する理由として考えられる多くの理由があります。ただし、質問で要求されている実行速度のみを考慮します。質問は、たとえば開発の速度を考慮していないようです。
2つの言語は同じバイトコードにコンパイルできますが、同じコードが生成されるわけではありません。
実際、バイトコードは特定の仮想マシンのコードのみです。エンジニアリング上の利点はありますが、特定のハードウェア向けに直接コンパイルする場合と根本的な違いはありません。したがって、同じマシン上で直接実行するためにコンパイルされた2つの言語を比較することも検討してください。
これは、言語の相対的な速度の問題は最初のコンパイラにさかのぼる古い問題であると言いました。
長年にわたり、専門家は手書きのコードはコンパイルされたコードよりも高速であると考えていました。つまり、機械語は、CobolやFortranなどの高レベル言語よりも高速であると見なされていました。そして、それはより速く、通常はより小さくなった。高レベル言語は、コンピューター科学者ではない多くの人々にとってはるかに使いやすいため、依然として開発されました。高級言語を使用するコストにも名前がありました:生成されたコードのサイズ(当時は非常に重要な問題)または実際に実行された命令の数に関係する拡張率。コンセプトは主に実験的なものでしたが、現在の標準ではコンパイラーがかなり単純な仕事をしていたため、比率は最初は1を超えていました。
したがって、機械語は、Fortranよりも高速でした。
もちろん、コンパイラーがより高度になるにつれて、それは長年にわたって変化し、現在ではアセンブリー言語でのプログラミングは非常にまれになっています。ほとんどのアプリケーションでは、アセンブリ言語プログラムは、コンパイラーの最適化によって生成されたコードと十分に競合しません。
これは、重要な問題の1つが、対象となる言語で使用できるコンパイラの品質、ソースコードを分析し、それに応じて最適化する能力であることを示しています。
この機能は、コンパイラの作業を容易にするために、ソースの構造的および数学的な特性を強調するために、言語の機能にある程度依存する場合があります。例えば、言語は、コンパイラーが最適化の目的でこれらのプロパティを使用できるように、ユーザー定義関数の代数的プロパティに関するステートメントを含めることができます。
言語のプログラミングパラダイムが、実際のマシンであろうと仮想マシンであろうと、コードを解釈するマシンの機能に近い場合、コンパイルプロセスが簡単になるため、より良いコードを生成できます。
もう1つのポイントは、言語で実装されたパラダイムが、プログラムされている問題のタイプに近いかどうかです。特定のプログラミングパラダイムに特化したプログラミング言語は、そのパラダイムに関連する機能を非常に効率的にコンパイルすることが期待されます。したがって、プログラミング言語の選択は、明快さと速度のために、プログラムされる問題の種類に適合したプログラミング言語の選択に依存する場合がある。
システムプログラミングでのCの人気は、おそらくCがマシンアーキテクチャに近く、システムプログラミングもそのアーキテクチャに直接関係しているという事実によるものです。
ロジックプログラミングと制約解決言語を使用して実行を高速化することにより、他の問題をより簡単にプログラミングできます。
複雑なリアクティブシステムは、そのようなシステムに関する非常に専門的な知識を具体化し、非常に高速なコードを生成するEsterelのような特殊な同期プログラミング言語で非常に効率的にプログラムできます。
または極端な例を挙げると、パーサーのプログラミングに使用される構文記述言語など、一部の言語は高度に専門化されています。パーサジェネレータは何もなく、そのような言語用のコンパイラではありません。もちろん、チューリング完全ではありませんが、これらのコンパイラーは、その専門性、つまり効率的な解析プログラムの作成に非常に適しています。知識の領域が制限されているため、最適化手法は非常に特殊化され、非常に細かく調整できます。これらのパーサージェネレーターは、通常、別の言語でコードを記述することで得られるものよりもはるかに優れています。制限されたクラスの問題に対して優れた高速のコードを生成するコンパイラーを備えた多くの高度に専門化された言語があります。
したがって、大規模なシステムを作成する場合、単一の言語に依存するのではなく、システムのさまざまなコンポーネントに最適な言語を選択することをお勧めします。もちろん、これは互換性の問題を引き起こします。
しばしば重要な別のポイントは、単にプログラムされているトピックのための効率的なライブラリの存在です。
最後に、速度が唯一の基準ではなく、コードの安全性(不正な入力やシステムエラーに対する回復力など)、メモリの使用、プログラミングの容易さなどの他の基準と矛盾する場合があります)、オブジェクトコードサイズ、プログラムの保守性など
速度が常に最も重要なパラメーターとは限りません。また、平均的な複雑さや最悪のケースの複雑さなどの複雑さなど、さまざまな装いが必要になる場合もあります。また、小さなプログラムのような大規模なシステムでは、速度が重要な部分と、重要性の低い部分があります。そして、それを前もって決定することは必ずしも容易ではありません。
最終的にすべてがCPU *で実行されますが、異なる言語の間にはさまざまな違いがあります。下記は用例です。
解釈言語 Python、Ruby、Matlabなど、一部の言語はコンパイルされずに解釈されます。つまり、PythonおよびRubyコードはマシンコードにコンパイルされず、その場で解釈されます。PythonとRubyを仮想マシンにコンパイルすることが可能です(次のポイントを参照)。この質問も参照してください。さまざまな理由により、通常、解釈はコンパイルされたコードよりも遅くなります。解釈自体が遅くなるだけでなく、最適化も難しくなります。ただし、コードがライブラリ関数(Matlabの場合)にほとんどの時間を費やす場合、パフォーマンスは低下しません。
仮想マシン一部の言語はバイトコードにコンパイルされます。バイトコードは発明された「マシンコード」であり、これが解釈されます。典型的な例は、JavaとC#です。バイトコードはその場でマシンコードに変換できますが、おそらくコードの実行速度は遅くなります。Javaの場合、移植性のために仮想マシンが使用されます。C#の場合、セキュリティなどの他の懸念があるかもしれません。
オーバーヘッド一部の言語は、セキュリティと効率を犠牲にしています。たとえば、Pascalの一部のバージョンは、境界外の配列にアクセスしないことを確認します。C#コードは「管理」されており、これにはコストがかかります。もう1つの一般的な例は、ガベージコレクションです。これは、プログラマの時間を節約しますが、実際のメモリ管理ほど効率的ではありません。例外処理やオブジェクト指向プログラミングのサポートのためのインフラストラクチャなど、オーバーヘッドの他のソースがあります。
*実際、今日の高性能システムはGPUやFPGAでもコードを実行します。
Yの代わりにXを選択するには、次のようなさまざまな要因があります。
C#やPythonなどのビジネスプロジェクトの開発に適した言語もありますが、C ++などのシステムプログラミングに適した言語もあります。
どのプラットフォームで作業するのか、どのアプリケーションを作成するのかを決定する必要があります。
どのプラットフォームでも使用できる「最速」のプログラミング言語は、対象のチップセットのアセンブリ言語です。そのレベルでは翻訳はありません。ただし、チップセットがどのように命令を実行するか、特に並行して実行できる命令については、ある程度の知識が必要です。
Cからアセンブリへの変換は非常に「浅い」ため、1対1に近くなりますが、読みやすくなります。ただし、移植性を向上させるための標準ライブラリにより、その上に多くのレイヤーがあります。コンパイラがアセンブリコードを取得するために必要なことはそれほど多くありません。一般的に、マシン固有の変更を行うための強力な最適化があります。
C ++はより豊富な言語を追加します。ただし、言語は非常に複雑になるため、コンパイラがプラットフォームに最適なコードを作成するのが難しくなります。
次に、スケールの反対側に移動します。通訳言語。これらは、作業の実行に加えて、コードを解析してマシンコールに変換するのに時間がかかるため、最も遅い傾向があります。
それからそれらの間にあります。一般に、プラットフォームに最適化された仮想マシン層があります。そして、コンパイラーは、実行する仮想マシンのコードを作成します。これは、perl、pascal、ruby、Pythonのように一度にすべて発生することもあります。または、javaのようないくつかの段階で。
これらの仮想マシンの一部は、中間バイトコードを変換するのではなく、マシンレベルのコードを作成することにより、ランタイムを高速化するJITコンパイラの概念を追加します。
一部の仮想マシンは、バイトコードからマシンコードへの変換が少ない低レベルです。移植性を保ちながら物事を高速化します。
*p++=*q++;
多くのマシンでのマシンコードに相当するものはより高速array1[i]=array2[i];
でしたが、多くのプロセッサーでは逆の場合が多いため、コンパイラーは前者のコードを後者に変換することがあります-ほとんど「浅い」変換ではありません。
-O0
と最適化は行われません。最適化はコンパイラで得られるボーナスですが、言語自体は1対1でアセンブリに変換できます。
まだ言及されていない点は、一部の言語では同じコードを何度も実行すると、常に同じアクションのシーケンスが実行されるということです。したがって、コンピューターは、コードのセクションが何をすべきかを一度決定するだけです。JavaScriptの「厳密な使用」方言の主な利点の1つは、JavaScriptエンジンがコードの一部を理解すると、次に実行されるときにその情報を利用できることです。「use strict」がなければ、できません。
たとえば、「use strict」がない場合、次のようなコードが含まれます。
function f() { return x; }
即時呼び出しコンテキストがある場合は変数Xを返すか、外部呼び出しコンテキストから変数Xを返すか、を返しUndefined
ます。さらに悪いことに、次のようなループで:
for (i=0; i<40; i+=1) { g(i); }
JavaScriptエンジンg()
は、i
[またはg
それ自体で何を行うか]を知る方法がありません。以来g
またはi
非常に合法的に変えることができるi
文字列には、JavaScriptエンジンは、単純にどちらかの関数呼び出しのがに何をしたかどうかを確認するために、ループ内の数値の加算と数値比較を使用していますが、各パス上の必須ループチェックを通してすることはできませんi
かループを通過するたびにそれらを検索する必要がなく、1回で済み、大幅な時間の節約になります。g
。対照的に、「use strict」[やや健全]方言では、JavaSciptエンジンは上記のコードを調べて、ループを通過するたびに同じ数値変数を使用し、同じ関数を呼び出すことを知ることができます。したがって、識別i
と機能のみが必要です。g
ここにはかなり専門的な答えがいくつかありますが、これはそれらに近いものではありませんが、あなたにとって直感的なものかもしれません。
できるだけ早くタスクを実行する必要がある場合、アセンブリで実行するコードを書きたいと何度も聞いたことがあるかもしれません。これは、タスクを完了するために実際に必要なコマンドのみを実行するためです。高レベル言語では、このタスクを数行で実装できますが、コンパイラーはそれらを機械語に翻訳する必要があります。この翻訳は、直接書くことができるため、必ずしも最小限のものではありません。これは、マシンがコマンドを実行するのに多くのクロックを費やすことを意味します。
コンパイラーは現在非常に洗練されていますが、最高のアセンブリー・プログラマーができるほど効果的ではありません。
この方向で続けると、これらの不必要なコマンドは、言語が高レベルになるにつれて(通常)量が増えます。(これはすべての高水準言語に100%当てはまるわけではありません)
したがって、特定のコードについて、XのマシンコードがYより短い場合、言語Xは言語Y(実行時)よりも高速です。
この質問は非常に複雑で多次元的であるため(たとえば、自動車のブランドを雑多な基準で比較するようなものです)、この質問に明確に答えることは困難ですが、Rosettaコードとして知られる優れたコードリポジトリを含む新しい科学的研究があります(ウィキペディアの概要)。Nanz and Furiaによるこの2014年の調査では、次の典型的な基準と、典型的な主観的なコード品質のまれな定量分析に基づいて、この問題を極めて明確かつ科学的に研究しています。要約には、客観的に根拠のある所見と一般化が含まれています。(うまくいけば、これらの結果に基づいた他の研究が将来行われるかもしれません。)
RQ1。どのプログラミング言語がより簡潔なコードを作成しますか?
RQ2。どのプログラミング言語が小さな実行可能ファイルにコンパイルされますか?
RQ3。実行時のパフォーマンスが優れているプログラミング言語はどれですか?
RQ4。メモリをより効率的に使用するプログラミング言語はどれですか?
RQ5。失敗しにくいプログラミング言語はどれですか?
要約-プログラミング言語に関する議論は、科学的というよりも宗教的な場合があります。どの言語がより簡潔または効率的であるか、開発者の生産性を高めるかについての質問は熱心に議論され、彼らの答えは逸話と根拠のない信念に基づいていることが多すぎます。この調査では、さまざまな言語の一般的なプログラミングタスクのソリューションのコードリポジトリであるRosetta Codeの未開発の研究の可能性を活用し、分析用の大規模なデータセットを提供します。私たちの調査は、主要なプログラミングパラダイムを表す8つの広く使用されている言語(手順:CおよびGo、オブジェクト指向:C#およびJava、機能:F#およびHaskell、スクリプト:PythonおよびRuby)の745タスクに対応する7,087ソリューションプログラムに基づいています。統計分析により、最も注目すべきことは次のとおりです。関数型言語およびスクリプト言語は、手続き型言語およびオブジェクト指向言語よりも簡潔です。Cは、大規模な入力で生の速度を達成するのに勝るものはありませんが、中程度のサイズの入力に対するパフォーマンスの違いはそれほど顕著ではなく、インタープリター言語でさえ競争力があります。コンパイル時により多くの欠陥をキャッチできる、コンパイル済みの厳密に型指定された言語は、インタプリタ型または弱い型指定の言語よりも実行時エラーを起こしにくい。これらの結果が開発者、言語設計者、教育者に与える影響について説明します。コンパイル時により多くの欠陥をキャッチできる場合、インタープリタ型または弱い型付けの言語よりも実行時エラーが発生しにくくなります。これらの結果が開発者、言語設計者、教育者に与える影響について説明します。コンパイル時により多くの欠陥をキャッチできる場合、インタープリタ型または弱い型付けの言語よりも実行時エラーが発生しにくくなります。これらの結果が開発者、言語設計者、教育者に与える影響について説明します。
コンピューター言語は、コンピューターに何をすべきかを説明するためのコマンドの単なる抽象化です。
コンピューター言語で記述Python
し、Cコンパイラー(cython)でコンパイルすることもできます。
これを念頭に置いて、コンピューター言語の速度を比較することはできません。
ただし、同じ言語のコンパイラをある程度まで比較できます。たとえば、GNU C
コンパイラ対Intel C
コンパイラ。(コンパイラベンチマークを検索)