1

私はメモリ割り当てのあるn00bですが、BeginInvokeタイプのデザインパターンでAsyncCallbacksを使用すると、メモリ割り当てが発生し、ガベージコレクタがより頻繁に呼び出される可能性があることを理解しようとしています。

たとえば、コールバックを使用して非同期で呼び出したいイベントを含むクラスがある場合、通常は次のように設定します。

方法I

public class PriceBook
{
    private double Value;

    public void UpdateValue(double Value)
    {
        this.Value = Value;
    }

    public event EventHandler ValueUpdated;
    private void DoValueUpdated(double Value)
    {
        if (ValueUpdated != null)
        {
            ValueUpdated.BeginInvoke(this, EventArgs.Empty, ValueUpdateCompleted, Value);
        }
    }

    private void ValueUpdateCompleted(IAsyncResult ar)
    {
        // Do something when event has finished being called.
    }
}

私が一緒に仕事をしている人は、この方法でBeginInvokeを呼び出すと、呼び出されるたびに新しいAsyncCallbackを作成することで、実際にメモリを割り当てると言います。それで、彼は代わりにこのようにすることを提案しました:

方法II

public class PriceBook
{
    private AsyncCallback ValueUpdateCallback;
    private double Value;

    public PriceBook1()
    {
        ValueUpdateCallback = ValueUpdateCompleted;
    }

    public void UpdateValue(double Value)
    {
        this.Value = Value;
        DoValueUpdated(Value);
    }

    public event EventHandler ValueUpdated;
    private void DoValueUpdated(double Value)
    {
        if (ValueUpdated != null)
        {
            ValueUpdated.BeginInvoke(this, EventArgs.Empty, ValueUpdateCallback, Value);
        }
    }

    private void ValueUpdateCompleted(IAsyncResult ar)
    {
        // Do something when event has finished being called.
    }
}

ご覧のとおり、ここではコンストラクターでAsyncCallbackを1回設定しました。方法IIは本当にメモリ割り当てを節約しますか?どちらの方法にも他に利点はありますか/私がやろうとしていることを達成するためのさらに良い方法はありますか?

  • ウィリアム
4

1 に答える 1

2

はい、これにより1つのデリゲート割り当てが節約されます。

これ

ValueUpdated.BeginInvoke(..., ValueUpdateCompleted, ...);

本当にこれです:

ValueUpdated.BeginInvoke(..., new AsyncCallback(ValueUpdateCompleted), ...);

これで割り当てを確認できます。

呼び出しがホットパス上にない場合、つまりパフォーマンスが重要ではない場合は、コードの保守性が低下しているため、デリゲートをキャッシュしないことをお勧めします。

また、スレッドプールの呼び出しは、そのデリゲートの割り当てよりもはるかにコストがかかります。これが違いを生むかもしれない状況を想像することはできません。

于 2012-08-25T16:09:57.307 に答える