如何更新频繁更改的类?每次更新还是更新字段?

问题描述:

我需要经常更新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我根本不需要锁定,因为引用更新是原子的。但是,我很可能会使用更多的内存,我可能会为GC创造更多的工作,因为

不,你的选择1是一样可能(通过促进更多的对象到下一代)造成的GC更多的负荷。

  1. 使用最明智,可维护的形式。在这种情况下,创建新的对象。

  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