3

更新:以下で説明する各手法のメモリへの影響をテストするプログラムを作成しました。それほど驚くことではありませが、確かに、.NET イベントを使用する従来のアプローチは、他のアプローチよりも多くのガベージを作成することがわかりました (つまり、他の 2 つの戦略はどちらも作成しないように見えるのとは対照的に、実際にはガベージを作成します)。ゴミは一切ありません)。

実際、速度に関するコストよりも、.NET イベントの引数のメモリオーバーヘッドに関心があることを最初から強調しておくべきでした。最終的には、メモリと速度の両方の点で、すべての実用的な目的のために、コストはごくわずかであることを認めなければなりません。それでも、「従来の」方法で多くのイベントを発生させると、何らかのコストかかること、そして極端な場合には、第 1 世代のガベージ コレクションにつながる可能性があることは興味深いと思いました。状況(私の経験では、システムがより「リアルタイム」である必要があるほど、ガベージが作成されている場所と、必要に応じてそれを最小限に抑える方法に注意することがより重要です)。TEventArgs


これはばかげた質問のように思えるかもしれません。たとえば、Windows フォームは、常に数百または数千のイベント (Control.MouseMoveイベントなど) が非常に急速に連続して発生するため、「高パフォーマンス」のシナリオと簡単に見なすことができます。しかし、クラスが高パフォーマンスでタイム クリティカルなコードで使用されることが予想される場合に、.NET イベントを使用してクラスを設計することが本当に合理的かどうか疑問に思っています。

私が持っている主な懸念は、イベントが発生/処理されるたびにインスタンス化する必要があるクラスから派生し、おそらくクラスであるEventHandler<TEventArgs>すべてのイベントに似たようなものを使用するという規則です。(単純な場合、明らかに、これは使用できるケースではありません。ただし、意味のある非定数情報が型に含まれていると仮定すると、インスタンス化がおそらく必要になります。)高性能ライブラリが作成されることを期待しています。TEventArgsEventArgsEventsArgsEventArgs.EmptyTEventArgs

とはいえ、私が考えることができる唯一の選択肢は次のとおりです。

  1. イベントに型にはまらないデリゲート型 (つまり、 ではない) を使用し、 、 などEventHandler<TEventArgs>のオブジェクトのインスタンス化を必要としないパラメーターのみを取得します( 、既存の文字列オブジェクトへの参照を渡すこともできます)。intdoublestring
  2. イベントを完全にスキップし、仮想メソッドを使用して、必要に応じてクライアント コードを強制的にオーバーライドします。これは基本的に前のアイデアと同じ効果を持っているようですが、より制御された方法です。

.NET イベントの GC プレッシャーに関する私の懸念は、そもそも根拠のないものですか? もしそうなら、私はそこに何が欠けていますか? または、私がリストした 2 つよりも優れた 3 番目の選択肢はありますか?

4

3 に答える 3

4

いや、Winforms イベントは CPU 時間ではなく人間の時間で発生します。現代のマシンに深刻な圧力をかけるほど速くマウスを動かすことは誰にもできません。トラバースされた個々のピクセルごとにメッセージはありません。

さらに言えば、デリゲート引数オブジェクトは常に第 0 世代のオブジェクトです。彼らは昇進するほど長くは続かない. それらの割り当てとガベージコレクションの両方は、非常に安価です。これは本当の問題ではありません。その幽霊を追いかけないでください。

于 2010-12-27T21:05:20.393 に答える
3

何かを行う前に、ある程度のプロファイリングを行って、実際に問題が発生することを確認する必要があります。UI マウスの動きなどの場合、イベントはマシンと比較して非常に低い頻度で発生するため、一般に GC の動作への影響はごくわずかです。.NET GC は、存続期間の短いオブジェクトをほとんど参照せずに収集するのに非常に優れていることに注意してください。これは、問題を引き起こす可能性がある多くの場所で参照される存続期間の短いオブジェクトです。

ただし、(何らかの理由で) これが実際に問題であることが証明された場合、コストを軽減するために考えられるアプローチがいくつかあります。

  1. 非標準のイベント デリゲート シグネチャを使用します。これは可能な代替手段としてすでに特定されていますが、イベント引数の型を構造体に制限する汎用シグネチャを常に使用できます。構造体をパラメーターとして渡すと、このデータのコピーを作成するという犠牲を払って、パラメーターがヒープに割り当てられるケースを減らす必要があります。

  2. 使用後にイベント引数のインスタンスをリサイクルする TEventArgs flyweight実装を使用します。イベント ハンドラーが他の場所で使用するためにパラメーターのインスタンスを保存しないようにする必要があるため、これは注意が必要です。ただし、このパターンを適切に実装すると、管理および収集が必要な軽量型のインスタンスの数を大幅に減らすことができます。

于 2010-12-27T21:10:26.613 に答える
2

あなたの懸念には十分な根拠があると思いますが、具体的なケースを検討する必要があります。

たとえば、特定の例では、スタックショットは、懸念すべき十分なコストを示します。イベントオブジェクトの作成/破棄ではなく、それらがトリガーする処理にコストがかかる場合があります。

最近よく目にするパフォーマンスの問題は「通知の暴走」です。イベントは、オブジェクトのプロパティを設定するだけかもしれません。大したことではありませんよね?しかし、そのプロパティ設定がスーパークラスによってインターセプトされる可能性があります。スーパークラスは、オブジェクトが含まれるコレクションを探し、それらのコレクション内のオブジェクトを追加/削除/再配置するための通知を送信します。これにより、ウィンドウが無効になったり、メニュー項目が無効になったりする可能性があります。作成/削除、または展開/閉​​じるツリー コントロール アイテムなど...

于 2010-12-27T20:46:51.430 に答える