JITと静的コンパイラ
以前の投稿ですでに述べたように、JITは実行時にIL /バイトコードをネイティブコードにコンパイルできます。そのコストは言及されましたが、結論には至りませんでした:
JITの大きな問題の1つは、すべてをコンパイルできないことです。JITのコンパイルには時間がかかるため、JITはコードの一部のみをコンパイルしますが、静的コンパイラは完全なネイティブバイナリを生成します。コンパイラーは単にJITを簡単に上回ります。
もちろん、C#(またはJava、またはVB)は通常、C ++よりも実行可能で堅牢なソリューションを生成する方が高速です(C ++に複雑なセマンティクスがあるためであり、C ++標準ライブラリは、興味深く強力ですが、完全版と比較するとかなり劣ります.NETまたはJavaの標準ライブラリのスコープ)なので、通常、C ++と.NETまたはJava JITの違いはほとんどのユーザーには見えません。重要なバイナリでは、C ++処理を呼び出すことができます。 C#またはJavaから(この種のネイティブコール自体が非常にコストがかかる場合でも)...
C ++メタプログラミング
通常は、C ++ランタイムコードを、C#またはJavaの同等のコードと比較していることに注意してください。ただし、C ++には、Java / C#よりも優れた機能が1つあります。それは、テンプレートメタプログラミングです。コード処理はコンパイル時に行われるため、コンパイル時間は大幅に増加し、ランタイムはゼロ(またはほぼゼロ)になります。
私はまだこれに実際の影響を見ています(私は概念のみで遊んでいましたが、それまでの違いは、JITの場合は実行の秒、C ++の場合はゼロでした)、ファクトテンプレートのメタプログラミングと並んで、これは言及する価値がありますささいな...
Edit 2011-06-10: C ++では、型の操作はコンパイル時に行われます。つまり、非ジェネリックコードを呼び出すジェネリックコードを生成します(たとえば、文字列から型Tへのジェネリックパーサー、認識される型Tの標準ライブラリAPIを呼び出します)。パーサーをユーザーが簡単に拡張できるようにすること)は非常に簡単で非常に効率的ですが、JavaまたはC#で同等のものを書くのはせいぜい苦痛であり、コンパイル時に型がわかっていても、実行時に常に遅くなり、解決されます。つまり、JITがすべてをインライン化することが唯一の希望です。
...
Edit 2011-09-20: Blitz ++(Homepage、Wikipedia)の背後にあるチームはそのようにして、明らかに、C ++テンプレートのメタプログラミングを介して、ランタイムの実行からコンパイル時間まで可能な限り移動することで、科学計算におけるFORTRANのパフォーマンスに到達することを目標としています。だから、私が上で書いた「私はこれに実際の生活の影響をまだ見ている」という部分は明らかに実際の生活に存在しています。
ネイティブC ++のメモリ使用量
C ++のメモリ使用量はJava / C#とは異なるため、異なる利点/欠点があります。
JIT最適化に関係なく、メモリへの直接ポインタアクセスほど高速なものはありません(プロセッサキャッシュなどを無視してください)。したがって、メモリ内に連続したデータがある場合、C ++ポインタ(つまり、Cポインタ... Caesarに期限を与えましょう)を介してデータにアクセスすると、Java / C#よりも数倍速くなります。また、C ++にはRAIIがあり、C#やJavaを使用するよりも多くの処理がはるかに簡単になります。C ++はusing
、そのオブジェクトの存在をスコープする必要はありません。また、C ++にはfinally
句がありません。これはエラーではありません。
:-)
また、C#プリミティブのような構造体にもかかわらず、C ++の「スタック上の」オブジェクトは、割り当てと破棄に費用がかからず、GCが独立したスレッドで動作してクリーニングを行う必要がありません。
メモリの断片化に関しては、2008年のメモリアロケータは1980年の古いメモリアロケータではなく、通常はGCと比較されます。C++の割り当てはメモリ内で移動できません。断片化が発生しない場合の最適化?適切なタスクに適切なアロケーターを使用することは、C ++開発者ツールキットの一部でなければなりません。さて、アロケータを書くのは簡単ではありません、そして、私たちのほとんどはもっと良いことをしています、そしてほとんどの場合、RAIIやGCは十分に優れています。
2011-10-04を編集:効率的なアロケーターの例:Windowsプラットフォームでは、Vista以降、低フラグメンテーションヒープがデフォルトで有効になっています。以前のバージョンの場合、WinAPI関数HeapSetInformationを呼び出すことにより、LFHをアクティブ化できます。他のOSでは、代替アロケーターが提供されています(https://secure.wikimedia.org/wikipedia/en/wiki/Malloc for a list)
現在、メモリモデルは、マルチコアおよびマルチスレッディングテクノロジの台頭により、やや複雑になっています。この分野では、.NETのほうが有利だと思います。一部の「ベアメタル」ハッカーが「マシンの近く」のコードを称賛するのは簡単です。しかし、今では、コンパイラーにその仕事を任せるよりも、手動でより良いアセンブリーを生成することはかなり困難です。C ++の場合、コンパイラは通常、10年前からハッカーよりも優れています。C#およびJavaの場合、これはさらに簡単です。
それでも、新しい標準C ++ 0xはC ++コンパイラに単純なメモリモデルを課し、C ++の効果的なマルチプロセッシング/並列/スレッド化コードを標準化(したがって単純化)し、コンパイラの最適化をより簡単かつ安全にします。しかし、その約束が守られているかどうかは、数年後にわかります。
C ++ / CLIとC#/ VB.NETの比較
注:このセクションでは、C ++ / CLI、つまりネイティブC ++ではなく.NETによってホストされるC ++について説明します。
先週、私は.NET最適化のトレーニングを受けましたが、いずれにせよ静的コンパイラーが非常に重要であることを発見しました。JITよりも重要です。
C ++ / CLI(またはその祖先、Managed C ++)でコンパイルされたまったく同じコードは、C#(またはVB.NET、コンパイラーがC#と同じILを生成)で生成された同じコードよりも数倍速い場合があります。
C ++スタティックコンパイラは、C#よりもすでに最適化されたコードを生成する方がはるかに優れていたためです。
たとえば、.NETでの関数のインライン展開は、バイトコードの長さが32バイト以下の関数に制限されています。そのため、C#の一部のコードは40バイトのアクセサーを生成しますが、これはJITによってインライン化されません。C ++ / CLIの同じコードは20バイトのアクセサーを生成し、これはJITによってインライン化されます。
別の例は一時変数で、C#コンパイラーによって生成されたILで言及されている間、C ++コンパイラーによって単純にコンパイルされます。C ++静的コンパイルの最適化により、コードが少なくなるため、より積極的なJIT最適化が再び許可されます。
この理由は、C ++ / CLIコンパイラーがC ++ネイティブコンパイラーの膨大な最適化技術から利益を得ているためと推測されていました。
結論
私はC ++が大好きです。
しかし、私が見る限り、C#やJavaの方が良いでしょう。C ++よりも高速なためではなく、それらの品質を合計すると、C ++よりも生産性が向上し、トレーニングの必要性が少なくなり、標準ライブラリが完全になるためです。そして、ほとんどのプログラムと同様に、それらの速度の違い(何らかの方法で)は無視できます...
編集(2011-06-06)
C#/。NETでの私の経験
私は5か月間、ほぼ独占的なプロ仕様のC#コーディングを行っています(これにより、CVとJavaで既にいっぱいになった私のCVと、C ++ / CLIが少し追加されます)。
WinForms(Ahem ...)とWCF(cool!)、WPF(Cool !!!! XAMLとraw C#の両方を使用しました。WPFは非常に簡単なので、Swingはそれに匹敵しないと思います)、およびC#4.0。
結論は、C ++よりもC#/ Javaで動作するコードを生成する方が簡単/高速ですが、C#で(そしてJavaでさらに)強力で安全で堅牢なコードを生成することは、C ++よりもはるかに難しいということです。理由はたくさんありますが、次のように要約できます。
- ジェネリックはテンプレートほど強力ではありません(効率的なジェネリックParseメソッド(文字列からTまで)、またはC#のboost :: lexical_castの効率的な同等物を記述して問題を理解してください)
- RAIIは比類のないままです(GCは依然としてリークする可能性があり(そう、私はその問題を処理する必要がありました)、メモリのみを処理します。
using
正しいDispose実装の作成が難しいため、C#でも簡単で強力ではありません)
- C#の
readonly
とJavaはfinal
C ++のようにどこに有用としてではないconst
(それが内蔵されている間C ++の特徴あなたは途方もない作業をせずにC#で読み取り専用の複雑なデータ例えばノードの(ツリー)公開することができる方法は、ありません。不変データは興味深いソリューションです、しかしすべてが不変にできるわけではないので、はるかに十分ではありません)。
したがって、C#は、何かが機能することを望む限り快適な言語であり続けますが、常に安全に機能するものを欲するときは苛立たしい言語です。
C#と同じ問題があるため、Javaはさらにイライラします。C#のusing
キーワードに相当するものがないため、非常に熟練した私の同僚は、リソースが適切に解放されることを確認するのに多くの時間を費やしましたが、C ++の相当するものは(デストラクタとスマートポインタを使用して)簡単になりました。
したがって、C#/ Javaの生産性向上はほとんどのコードで目に見えると思います...コードをできる限り完璧にする必要がある日までは。その日、あなたは痛みを知るでしょう。(あなたは私たちのサーバーとGUIアプリから尋ねられたものを信じられないでしょう...)。
サーバー側のJavaおよびC ++について
私は建物の反対側でサーバーチーム(GUIチームに戻る前に2年間働いた)と連絡を取り続け、興味深いことを学びました。
昨年、Javaには多くのフレームワーク/ツールがあり、メンテナンス、デプロイなどが簡単であるため、Javaサーバーアプリは古いC ++サーバーアプリに置き換わる傾向にありました。
...低レイテンシの問題が最後の数ヶ月で醜い頭を育てるまで。次に、熟練したJavaチームが試みた最適化に関係なく、Javaサーバーアプリは、実際には最適化されていない古いC ++サーバーとの競争を単純かつ完全に失いました。
現在、決定は、パフォーマンスが依然として重要であり、低レイテンシの目標に関心がない場合にJavaサーバーを一般的に使用するように維持し、低レイテンシと超低レイテンシのニーズに合わせてすでに高速のC ++サーバーアプリケーションを積極的に最適化することです。
結論
予想されるほど単純なものはありません。
Java、さらに多くのC#は、高速なコーディングが可能で、すぐに結果が得られる広範な標準ライブラリとフレームワークを備えたクールな言語です。
しかし、生のパワー、強力で体系的な最適化、強力なコンパイラサポート、強力な言語機能、絶対的な安全性が必要な場合、JavaとC#は、競争力を維持するために必要な最後の欠けているが重要な品質の品質を獲得することを困難にします。
平均品質のコードを作成するためにC ++ / JavaよりもC#/ Javaの開発者の方が時間と経験の少ない開発者を必要とするかのようですが、一方で、完璧で高品質のコードが必要になった瞬間、結果を得るのが突然簡単かつ迅速になりました。まさにC ++で。
もちろん、これは私自身の認識であり、おそらく私たちの特定のニーズに限定されています。
しかし、それでも、今日はGUIチームとサーバー側チームの両方で起こっています。
もちろん、何か新しいことが起こったらこの投稿を更新します。
編集(2011-06-22)
「パフォーマンスに関しては、C ++が大差で勝っていることがわかりました。しかし、C ++には最も広範なチューニング作業も必要でした。その多くは、平均的なプログラマーには利用できない高度なレベルで行われました。
[...] Javaバージョンはおそらく実装が最も簡単でしたが、パフォーマンスを分析するのが最も困難でした。具体的には、ガベージコレクションに関する影響は複雑で、調整が非常に困難でした。」
出典:
編集(2011-09-20)
「Facebookでの今後の言葉は、「合理的に書かれたC ++コードは高速に実行されるだけである」ということです。これは、PHPおよびJavaコードの最適化に費やされた膨大な労力を強調しています。逆説的に、C ++コードは他の言語よりも書くのが難しいですが、効率的なコードは[他の言語よりもC ++で書く方が]ずっと簡単です。 "
– // build /のHerb Sutter、Andrei Alexandrescuを引用
出典: