web-dev-qa-db-ja.com

パフォーマンスのためにCで書く?

Cは通常、C++よりもパフォーマンス上の利点があるとよく耳にします。 MSVCがCの最新の標準をサポートしているようには見えないが、最新のC99をサポートしていることに気づくまで、私はそれ以外に何も考えませんでした(私の知る限り)。

OpenGLでレンダリングするためのコードを含むライブラリを作成して、再利用できるようにするつもりでした。グラフィックスに関しては、パフォーマンスの向上を歓迎するので、Cでライブラリを作成することを計画していました。

しかし、それは本当に価値があるでしょうか?ライブラリを使用するコードはC++で記述される可能性が高く、一般的にC++でコーディングすることを好みます。

ただし、パフォーマンスにわずかな違いが生じる場合は、Cを使用します。

また、このライブラリはWindows/OS X/Linuxで動作するように作成するものであり、すべてをネイティブにコンパイルする可能性があります(MSVC for Windows、ClangまたはGCC for OS X、およびGCC for Linux)。 。またはおそらくすべてのインテルのコンパイラ)。

私は周りを見回して、いくつかのベンチマークなどを見つけましたが、私が見たものはすべて、MSVCとClangではなくGCCを扱っています。また、ベンチマークでは、使用される言語の標準については触れられていません。誰かこれについて何か考えがありますか?

編集: 2年以上の経験を経て、この質問に対する私の見解を共有したいと思いました。この質問をしていたプロジェクトをC++で書くことになりました。私がCで同時期に別のプロジェクトを開始したとき、可能な限り少量のパフォーマンスを引き出そうとしていて、プロジェクトをCでリンクできるようにする必要がありました。2か月前、私は本当にマップが必要で高度な文字列操作。私はC++標準ライブラリのこの機能を知っていて、標準ライブラリのこれらの構造は、適度な時間でCに実装できるマップや文字列よりもパフォーマンスが高く、安定している可能性が高いという結論に達しました。 Cでリンク可能であるという要件は、C++コードへのCインターフェースを作成することで簡単に満たされました。これは、不透明型ですばやく実行されました。 C++でのライブラリの書き換えは、Cでの書き込みよりもはるかに高速に行われるようで、特にメモリリークなどのバグが発生しにくくなりました。また、プラットフォーム固有の実装を使用するよりもはるかに簡単な標準ライブラリスレッドライブラリを使用することもできました。結局、C++でライブラリを作成することで、パフォーマンスがわずかに低下するだけで、大きなメリットが得られたと思います。 C++バージョンのベンチマークはまだ行っていませんが、私が書いたものよりも標準のライブラリデータ構造を使用することで、ある程度のパフォーマンスが得られた可能性さえあると思います。

32
danielunderwood

Cのパフォーマンスについてreasonの方が簡単であるため、CはC++よりも高速であるとよく言われるでしょう。たとえば、C++コードの一部を見てもすぐには表示されないコピーや暗黙の変換が存在する場合があります。

次のステートメントを見てみましょう:

_foo->doSomething(a + 5, *c);
_

さらに、doSomethingに次のシグネチャがあると仮定します。

_void doSomething(int a, long b);
_

ここで、この特定のステートメントのパフォーマンスへの影響の可能性を分析してみましょう。

Cでは、その意味が非常に明確です。 fooは、構造体へのポインタのみにすることができ、doSomethingは、関数へのポインタでなければなりません。 _*c_はlongを逆参照し、_a + 5_は整数の加算です。唯一の不確実性はaのタイプに起因します。それがintでない場合、変換が行われます。それとは別に、この1つのステートメントのパフォーマンスへの影響を簡単に数値化できます。

それではC++に切り替えましょう。同じステートメントで、パフォーマンス特性が大きく異なる可能性があります。

  1. doSomethingは、非仮想メンバー関数(安い)、仮想メンバー関数(もう少し高価)、_std::function_、ラムダなどになる可能性があります。さらに悪いことに、fooは_operator->_をオーバーロードするクラス型であり、未知の複雑さの操作がいくつかあります。したがって、doSomethingを呼び出すコストを定量化するには、foodoSomethingの正確な性質を知る必要があります。
  2. aは、整数、または整数への参照(追加の間接参照)、またはoperator+(int)を実装するクラス型にすることができます。演算子は、暗黙的にintに変換可能な別のクラスタイプを返すこともできます。繰り返しになりますが、パフォーマンスコストはステートメントだけからは明らかではありません。
  3. cは、operator*()を実装するクラス型である可能性があります。 _long*_などへの参照にすることもできます。

あなたは写真を取得します。 C++の言語機能により、単一ステートメントのパフォーマンスコストを数値化することは、Cの場合よりもはるかに困難です。さらに、_std::vector_、_std::string_などの抽象化は、パフォーマンス特性を持つC++で一般的に使用されます動的メモリ割り当てを非表示にします(@Ianの回答も参照してください)。

つまり、結論としては、一般的に、CまたはC++を使用して達成可能なパフォーマンスに違いはありません。しかし、実際にパフォーマンスが重要なコードでは、hiddenのパフォーマンスペナルティがはるかに少ないため、人々はしばしばCの使用を好む。

89
lethal-guitar

C++で記述されたコードは、特定のタイプのタスクについて、Cよりも高速である場合があります。

C++を使用する場合は、C++を使用してください。パフォーマンスの問題は、ソフトウェアのアルゴリズムによる決定と比較して重要ではなくなります。

30
whatsisname

C++の設計原則の1つは、使用しない機能には料金を払わないことです。したがって、C++でコードを記述し、Cに存在しない機能を使用しない場合、結果として得られるコンパイル済みコードのパフォーマンスは同等になります(ただし、これを測定する必要があります)。

たとえば、構造体や関連する関数の束と比較して、クラスの使用にはほとんどコストがかかりません。仮想関数は少しコストがかかります。アプリケーションに重要かどうかを確認するには、パフォーマンスを測定する必要があります。他のC++言語機能についても同様です。

23
Greg Hewgill

高レベルの言語が時々遅くなる1つの理由は、低レベルの言語よりも多くのメモリ管理を舞台裏で隠すことができるためです。

低レベルの詳細を抽象化する言語(またはライブラリ、APIなど)は、コストのかかる操作を潜在的に隠す可能性があります。たとえば、一部の言語では、文字列から末尾の空白を単に削除すると、メモリ割り当てと文字列のコピーが生成されます。特にメモリの割り当てとコピーは、タイトなループで繰り返し発生する場合、コストが高くなる可能性があります。

この種のコードをCで記述した場合、それは明らかに明白です。 C++では、割り当てとコピーがどこかでクラスに抽象化される可能性があるため、そうではない可能性があります。それらは、無害に見えるオーバーロードされた演算子またはコピーコンストラクターの背後に隠れている場合もあります。

必要に応じてC++を使用してください。しかし、抽象化の下に何があるのか​​わからないときでも、抽象化の便利さのように見えることに惑わされないでください。

もちろん、プロファイラーを使用して、コードを本当に遅くしているものを見つけてください。

14
Ian Goldby

価値があるのは、拡張機能セット用のライブラリをC++ 11で作成することです。共有ポインター、例外、一般的なプログラミング、その他のC++のみの機能などを利用できるのが好きです。 C++ 11が好きなのは、気になるすべてのプラットフォームでC++ 11のかなりの部分がサポートされていることがわかったからです。 Visual Studio 2013には たくさん のコア言語機能とライブラリ実装の準備が整っており、残りの追加に取り組んでいると思われます。ご存知のとおり、ClangとGCCはどちらも機能セット全体をサポートしています。

そうは言っても、私は最近、ライブラリー開発に関する非常に優れた戦略について読みました。これは、クエリに直接関連していると思います。記事のタイトルは "C++例外でニースを演じるCエラー処理スタイル" Stefanu Du Toitはこの戦略を "砂時計"パターンと呼んでいます。記事の最初の段落:

「砂時計」パターンと呼ばれるものを使用して多くのライブラリコードを記述しました。ライブラリを実装し(私の場合、通常はC++を使用)、ライブラリへの唯一のエントリポイントとなるC APIでそれをラップします。次に、そのC APIをC++または他の言語でラップして、豊富な抽象化と便利な構文を提供します。ネイティブクロスプラットフォームコードに関しては、C APIは比類のないABIの安定性とFFIを介した他の言語への移植性を提供します。私は、APIをCのサブセットに制限しています。これは、さまざまなFFIに移植可能であり、ライブラリが内部データ構造の変更をリークしないようにします。これについては、今後のブログ投稿でさらに期待します。


次に、主な懸念事項であるパフォーマンスについて説明します。

ここでの他の多くの回答と同様に、どちらの言語でコードを書くことも、パフォーマンスの観点で同様に機能することをお勧めします。個人的な見地からは、言語機能により、C++で正しいコードを書く方が簡単だと思いますが、それは個人的な好みだと思います。いずれにせよ、コンパイラーは本当に賢く、とにかくあなたよりも優れたコードを書く傾向があります。つまり、コンパイラはコードを最適化する可能性が高いということです。

私は多くのプログラマーがこれを言っていることを知っていますが、最初にすべきことは、コードを記述し、それをプロファイリングして、プロファイラーが提案する最適化を行うことです。あなたの時間は、機能を作成し、ボトルネックがどこにあるかがわかると、それを最適化するのに費やす時間を大幅に短縮できます。


次に、言語機能と最適化が実際にどのように機能するかについての楽しい読み物を紹介します。

std :: unique_ptrにはオーバーヘッドがありません

constexpはコンパイル時の計算を可能にします

セマンティクスを移動すると、不要な一時オブジェクトが防止されます

5
vmrob

C++とCのパフォーマンスの違いは、厳密に言えば、言語の何かによるものではなく、何をしたいのかという点にあります。クレジットカードと現金のようなものです。それはあなたがより多くの支出をすることはありませんが、あなたが非常に訓練されていない限り、とにかくあなたは費やします。

C++で記述されたプログラムの例 は、パフォーマンスを大幅にチューニングしたものです。言語に関係なく、積極的なパフォーマンスチューニングを行う方法を知っている必要があります。 this video に示すように、私が使用する方法はランダムな一時停止です。

C++が誘惑するコストのかかることは、過剰なメモリ管理、通知スタイルのプログラミング、多層カウンター(@Ianによる)へのプログラムカウンターの信頼、低速の非表示などです。

4
Mike Dunlavey

Cは、両方の言語で同じことを行う場合、C++に比べてパフォーマンス上の利点はありません。適切なCプログラマーが作成した古いCコードを使用して、それを有効で同等のC++コードに変換することができます。しかし、ほとんどの人はしません)。

(1)標準のC++ライブラリを使用して、ライブラリを使用せずにはるかに速く簡単に実行できることを実行した場合、または(2)標準のC++ライブラリを使用した場合悪いCでライブラリを再実装するよりもはるかに簡単かつ迅速に物事を行うため。

2
gnasher729