0

InstrumentInfoクラスを頻繁に更新する必要があります。あるスレッドからこのクラスを更新し、別のスレッドからアクセス (読み取り) します。

Instrumentクラスがあります。Instrument私が維持する必要がある各クラスについてInstrumentInfo

// omit class Instrument as not improtant

public class InstrumentInfo
{
    public string Name { get; set; }
    public TradingStatus Status { get; set; }
    public decimal MinStep;
    public double ValToday;
    public decimal BestBuy;
    public decimal BestSell;
}

public class DerivativeInfo : InstrumentInfo
{
    public DateTime LastTradeDate { get; set; }
    public DateTime ExpirationDate { get; set; }
    public string UnderlyingTicker { get; set; }
}

// i do have several more subclasses

2 つのオプションがあります。

  1. InstrumentInfoごとに1 つだけ作成しますInstrument。一部のフィールドが更新されると、たとえばBestBuy、このフィールドの値が更新されます。クライアントはInstrumentInfo一度だけ取得し、アプリケーションの存続期間全体で使用する必要があります。
  2. 更新ごとに、 の新しいインスタンスを作成しますInstrumentInfo。クライアントは、InstrumentInfo の最新のコピーを毎回取得する必要があります。

更新がアトミックであることが保証されていない1ため、ロックする必要があります。decimal DateTime stringしかし、オブジェクトを元に戻す必要はありません。

更新はアトミックで2あるため、ロックする必要はまったくありません。referenceしかし、新しいオブジェクトを開始する (そしてすべてのフィールドを初期化する) 必要があるたびに、より多くのメモリを使用する可能性が高く、おそらく GC のためにより多くの作業を作成することになります。

1実装

    private InstrumentInfo[] instrumentInfos = new InstrumentInfo[Constants.MAX_INSTRUMENTS_NUMBER_IN_SYSTEM];

    // invoked from different threads
    public InstrumentInfo GetInstrumentInfo(Instrument instrument)
    {
        lock (instrumentInfos) {
            var result = instrumentInfos[instrument.Id];
            if (result == null) {
                result = new InstrumentInfo();
                instrumentInfos[instrument.Id] = result;
            }
            return result;
        }
    }

    ...........
    InstrumentInfo ii = GetInstrumentInfo(instrument);
    lock (ii) {
        ii.BestSell = BestSell;
    }

2実装:

    private InstrumentInfo[] instrumentInfos = new InstrumentInfo[Constants.MAX_INSTRUMENTS_NUMBER_IN_SYSTEM];

    // get and set are invoked from different threads
    // but i don't need to lock at all!!! as reference update is atomic
    public void SetInstrumentInfo(Instrument instrument, InstrumentInfo info)
    {
        if (instrument == null || info == null)
        {
            return;
        }
        instrumentInfos[instrument.Id] = info;
    }

    // get and set are invoked from different threads
    public InstrumentInfo GetInstrumentInfo(Instrument instrument)
    {
        return instrumentInfos[instrument.Id];
    }
    ....
    InstrumentInfo ii = new InstrumentInfo {
        Name = ..
        TradingStatus = ...
        ...
        BestSell = 
    }

    SetInstrumentInfo(instrument, ii); // replace InstrumentInfo

それで、あなたはどう思いますか?2ロックのないコードが好きなのでアプローチしたい!lock参照を置き換えるだけなので、まったく必要ないというのは正しいですか?2それが好ましいことに同意しますか?どんな提案でも大歓迎です。

4

2 に答える 2

2

いくつかの無関係な点を考慮する必要があります。

  1. もちろん、ロックなしで行ける場合は、ロックなしで行く必要があります。また、マルチスレッドを使用する場合は、不変オブジェクトを優先してください。

  2. 一方、不変オブジェクト

    • ひずみ記憶
    • 「アンチOOP」と見なされます
    • クライアントコードによって誤って消費される可能性があります (人々はそれらの操作に慣れていないため)
  3. 2 番目のアプローチでは、いくつかのスレッドがset異なる開始仮定で情報を提供する可能性があるため、いくつかの同時実行処理戦略が必要です。

  4. 参照割り当てがアトミックかどうかはわかりません。もしそうなら、なぜCLRは持っているのInterlocked.Exchange<T>ですか? これを指摘してくれた Henk Holterman に感謝します。

于 2012-08-14T09:17:03.230 に答える
2

参照の更新はアトミックで2あるため、ロックする必要はまったくありません。しかし、より多くのメモリを使用する可能性が高く、おそらく GC のためにより多くの作業を作成するでしょう。

いいえ、あなたのオプション1は、(より多くのオブジェクトを次世代に昇格させることによって) GC により多くの負荷を引き起こす可能性があります。

  1. 最も賢明で保守しやすい形式を使用してください。この場合、新しいオブジェクトを作成します。

  2. 遅くなる可能性があると「考えている」ものに基づいて最適化しないでください。プロファイラーを使用します。

于 2012-08-14T09:09:59.490 に答える