2012-08-14 89 views
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 

我有兩個選擇:

  1. 創建只有一個InstrumentInfo每個Instrument。當某些字段更新時,例如BestBuy只是更新該字段的值。客戶只能獲得InstrumentInfo一次,並在整個應用程序生命週期中使用它。
  2. 在每次更新時創建InstrumentInfo的新實例。客戶應該每次獲取InstrumentInfo的最新副本。

隨着1我確實需要加鎖,因爲decimalDateTimestring更新不能保證是原子。但我不需要重新定義對象。

With 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是首選嗎?歡迎任何建議。

+0

只是爲了防止*鎖定,鎖定「私有靜態只讀對象」而不是您的儀器信息陣列 - 就像防禦性編碼練習一樣。 – Adam 2012-08-14 09:13:14

+0

@codesparkle - 鎖定一個'static'對象會導致(多)更多的爭用。目前的方法('ii'不是陣列)看起來不錯。 – 2012-08-14 09:15:42

+0

@HenkHolterman他鎖定了'lock(instrumentInfos){'這是一個數組。 'ii'與它無關。但是你是對的,把它變成靜態是沒有必要的。只讀會做。 – Adam 2012-08-14 09:17:07

回答

2

隨着2我根本不需要鎖定,因爲引用更新是原子的。但是,我很可能會使用更多的內存,我可能會爲GC創造更多的工作,因爲

不,你的選擇1是一樣可能(通過促進更多的對象到下一代)造成的GC更多的負荷。

  1. 使用最明智,可維護的形式。在這種情況下,創建新的對象。

  2. 不要根據你「想象」的速度進行優化。使用分析器。

2

你應該考慮幾個不相關的點。

  1. 當你不帶鎖的時候,你當然應該沒有它們。而當你進行多線程時,更喜歡不可變的對象。

  2. 在另一側,不可變對象

    • 應變存儲器
    • 被認爲是「抗OOP」
    • 可以由客戶機代碼被錯誤地消耗(因爲人們不使用和他們一起工作)
  3. 您的第二種方法仍然需要一些併發處理策略,因爲幾個線程可能set infotos與di不同的開始假設。

  4. 我不確定引用賦值是否爲原子。如果是這樣,爲什麼CLR有 Interlocked.Exchange<T>感謝Henk Holterman指出了這一點。

+0

*因爲當*是不可變對象被認爲是「反OOP」時? – Adam 2012-08-14 09:17:37

+0

4)參考分配被記錄爲原子的。 – 2012-08-14 09:21:30

+0

@codesparkle從對象崇拜者和功能崇拜者之間的聖戰發明開始。不是我同意任何方面,我只是警告可能的邊緣點。 – 2012-08-14 09:23:19