如何更新频繁更改的类?每次重新安排或只是更新字段?

时间:2012-08-14 09:05:00

标签: c#

我需要经常更新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副本。
  3. 使用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是首选的?欢迎任何建议。

2 个答案:

答案 0 :(得分:2)

  

使用2我根本不需要锁定,因为参考更新是原子的。但我可能会使用更多的内存,我可能会为GC创建更多的工作,因为

不,您的选项1可能会导致更多的GC负载(通过向下一代推广更多对象)。

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

  2. 不要根据您的想法进行优化可能会变慢。使用分析器。

答案 1 :(得分:2)

你应该考虑几个不相关的观点。

  1. 当你没有锁时,你应该没有它们,当然。当你选择多线程时,更喜欢不可变对象。

  2. 另一方面,不可变对象

    • 应变记忆
    • 被视为"反OOP"
    • 可能被客户端代码错误地使用(因为人们不使用它们)
  3. 你的第二种方法仍然需要一些并发处理策略,因为有几个线程可能set使用不同的起始假设信息。

  4. 我不确定引用赋值是否为原子。如果是,为什么CLR有Interlocked.Exchange<T>感谢Henk Holterman指出这一点。