10

私は今しばらくの間共有ポインターを使用しており、プログラムにパフォーマンスの問題があります...共有ポインターがパフォーマンスの低下につながるかどうかを知りたいです。もしそうなら、どのくらい難しいですか?どうもありがとう。

私のプログラムは std::tr1::shared_ptr を使用してマルチスレッド化されています

4

7 に答える 7

13

アプリが65バイトのGoogleプロトコルメッセージまたは85バイトのASN.1メッセージに含まれる可能性のある約700バイトのXMLメッセージを渡す場合、おそらく問題にはなりません。しかし、1秒間に数百万もの処理を行っている場合は、ポインターの受け渡しに2回の完全な読み取り変更書き込み(RMW)サイクルを追加するコストを却下しません。

フルリードモディファイライトは50nsのオーダーであるため、2つは100nsです。このコストは、lock-incとlock-decのコストです。2つのCASと同じです。これは、Windowsのクリティカルセクションの予約とリリースの半分です。これは、単一の1マシンサイクルプッシュ(2.5GHZマシンで400 PICO秒)と比較されます。

また、これには、実際にカウントを含むキャッシュラインを無効にするためのその他のコスト、他のプロセッサに対するBUSロックの影響なども含まれていません。

const参照によるスマートポインタの受け渡しは、ほとんどの場合、常に推奨されます。呼び出し先が、ポインターの存続期間を保証または制御したいときに、新しい共有ポインターを作成しない場合、それは呼び出し先のバグです。スマートポインタを値でカウントするスレッドセーフリファレンスを気ままに渡すことは、パフォーマンスへの影響を求めているだけです。

参照カウントポインタを使用すると、間違いなく存続期間が短縮されますが、共有ポインタを値で渡して、呼び出し先の欠陥から保護しようとするのは、まったく意味がありません。

参照カウントを過度に使用すると、1秒あたり1mmのメッセージ(mps)を処理​​できる洗練されたプログラムが、同じハードウェアで150kmpsを処理する太いプログラムに変わる可能性があります。突然、サーバーのラックが半分になり、年間10000ドルの電力が必要になります。

参照カウントなしでオブジェクトの存続期間を管理できれば、常に良い結果が得られます。

単純な改善の例は、オブジェクトをファンアウトしようとしていて、ファンアウトの幅(たとえばn)が各ファンアウトで個別に増加するのではなく、nずつ増加することがわかっている場合です。

ところで、CPUがロックプレフィックスを確認すると、実際には「これは問題になります」と表示されます。

そうは言っても、ホットスポットを確認する必要があることに同意します。

于 2009-10-13T05:02:01.500 に答える
9

データが与えられた場合、この質問に正しく答えることは事実上不可能です。アプリケーションでパフォーマンスの問題を引き起こしている原因を正確に知る唯一の方法は、プログラムでプロファイラーを実行して出力を調べることです。

そうは言っても、shared_ptr がスローダウンを引き起こしている可能性はほとんどありません。shared_ptr 型と多くの初期の自家製バリアントは、ますます多くの C++ プログラムで使用されています。私自身、仕事で使用しています(自宅の専門家)。仕事用アプリケーションのプロファイリングに多くの時間を費やしてきましたが、shared_ptr が私のコードやアプリケーション内で実行されている他のコードの問題に近づいたことは一度もありません。エラーが別の場所にある可能性が高いです。

于 2009-10-12T18:02:12.463 に答える
5

プログラムにパフォーマンス上の問題があるように見える場合、その問題が何であるかを推測し始めるのはまったく自然なことですが、賭けをしたい場合は、まったく別のものである可能性がほぼ 100% あります。プロファイリングで問題が見つかる場合があります。これは私が使用する方法です。

于 2009-10-12T20:13:33.540 に答える
5

共有ポインタは参照カウントされます。特にマルチスレッドを使用している場合、参照カウントのインクリメントとデクリメントにはかなりの時間がかかる可能性があります。ここでマルチスレッドが問題となる理由は、スレッド間で共有ポインターを渡すと、それらのスレッド間で参照カウントが共有されることになるため、すべての操作をスレッド間で同期する必要があるためです。それは物事をかなり遅くすることができます。

編集:スレッドのインターロックがどれだけ遅いかを気にする人は、いくつかのかなり単純な操作を行うことができるため、CoW Stringsのいくつかの実装を使用した Herb Sutter のテストを参照してください。彼のテストは完璧とはほど遠いものですが (たとえば、彼は Windows でのみテストしました)、予想されるスローダウンの種類についてある程度のアイデアを得ることができます。shared_ptr<charT>ほとんどの実用的な目的のために、CoW 文字列は、多くの (無関係な) メンバー関数が追加された のようなものと考えることができます。

于 2009-10-12T18:01:59.843 に答える
3

ほとんどの場合、ポインターを渡すのにほとんどの時間を費やす必要があります。

通常、共有ptrsの影響は小さく、それらが問題になるエッジケースを構築することさえ困難です(適切な実装と適切に最適化されたコンパイラを想定しています)。

共有ptrの影響:

  • 割り当てサイズの増加。
    これは、非常に小さなオブジェクト (数千万などshared_ptr<int>) への共有ポインタが多数ある場合、および/またはメモリ制限近くで動作している場合にのみ問題になります。余分な割り当てが内部ループ内のキャッシュ/NUMA レベルを超えると、パフォーマンスが大幅に低下する可能性がわずかにあります。

  • 割り当て
    shared_ptr数の増加は、追跡オブジェクト (参照カウント、ウィーク カウント、および削除機能) をすべてコーティングします。これにより、ヒープに圧力がかかり、割り当てと割り当て解除の合計数が多い場合、一般的な速度低下が発生する可能性があります。を使用して参照先と追跡オブジェクトを単一の割り当てに入れる
    ことで回避できますmake_shared

  • 参照カウント
    は、ポインターのコピーのコストを増加させます。シングル スレッド アプリケーションでは、ほとんどの時間をポインターのコピーに費やしていることに気付くでしょう。マルチスレッド アプリケーションでは、同じポインターで高い競合が必要になります。関数の引数として eg を
    渡すことで、多くの場所でコピーのコストを回避できます。shared_ptr<T> const &

  • 逆参照
    追加の逆参照コストは、最適化コンパイラのリリース ビルドではゼロです。デバッグ ビルドは、多くの場合、関数呼び出しと追加の NULL チェックに相当します。それでも、特にデバッグ ビルドでは、違いを生むためにポインターの逆参照にほとんどの時間を費やさなければなりません。


追加情報がなければ、私たちはあなたを助けることができません. 「パフォーマンスの問題」が何であるか (一般的な動作の遅さ、特定の操作に時間がかかる、大量のスワッピング)、およびいくつかの重要な数値 (アプリの機能、スマート ポインターの数、それらがコピーされる頻度) を説明する必要があります。そして、ジャグリングスマートポインター以外に実行する他の操作。

または、パフォーマンス モニターやプロファイラーを使用して、スローダウンの原因を突き止め、特定のボトルネックがあるかどうかを学習します。

于 2009-10-12T18:36:27.120 に答える
1

パフォーマンスを損なう可能性があることの 1 つは、過度に shared_ptr を関数パラメーターとして渡すことです。その解決策は、参照を shared_ptr に渡すことです。ただし、これはマイクロ最適化であるため、本当に必要な場合にのみ実行してください

編集:これについて考えるとき、最適化するためのより良い方法があります:

  • ポインターを過度に渡す場合は、オブジェクトをドラッグするのではなく、オブジェクトに何かをさせる必要があります。
  • ポインターの代わりにオブジェクトへの (const) 参照を渡すことができます
  • ポインターを変更する必要があるときにポインターへの参照を渡す
于 2009-10-12T20:25:39.053 に答える
0

パフォーマンスについて推測しないでください。コードをプロファイリングします。

于 2009-10-12T21:05:25.977 に答える