C# 如何更新频繁更改的类?每次恢复还是只更新字段?

C# 如何更新频繁更改的类?每次恢复还是只更新字段?,c#,C#,我需要经常更新InstrumentInfo类。我从一个线程更新这个类,并从另一个线程访问(读取) 我有仪器课。对于每个仪器类别,我需要维护仪器信息: // omit class Instrument as not improtant public class InstrumentInfo { public string Name { get; set; } public TradingStatus Status { get; set; } public decimal

我需要经常更新
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
我有两个选择:

  • 为每个
    仪器
    只创建一个
    仪器信息
    。当某些字段更新时,例如
    百思买
    只需更新此字段的值。客户端应仅获取一次
    InstrumentInfo
    ,并在整个应用程序生命周期内使用它
  • 每次更新时,创建
    InstrumentInfo
    的新实例。客户每次都应获取InstrumentInfo的最新副本
  • 对于
    1
    我确实需要锁定,因为
    十进制
    日期时间
    字符串
    更新不保证是原子的。但我不需要恢复这个物体

    使用
    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
    
    那你觉得呢?我想使用approach
    2
    ,因为我喜欢没有锁的代码!我完全不需要
    ,因为我只是替换了引用,对吗?您是否同意首选
    2
    ?欢迎提出任何建议

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

    不,您的选项
    1
    同样可能导致GC上的负载增加(通过将更多对象升级到下一代)

  • 使用最合理、可维护的表单。在这种情况下,创建新对象

  • 不要根据您“认为”可能较慢的内容进行优化。使用分析器

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

    不,您的选项
    1
    同样可能导致GC上的负载增加(通过将更多对象升级到下一代)

  • 使用最合理、可维护的表单。在这种情况下,创建新对象

  • 不要根据您“认为”可能较慢的内容进行优化。使用分析器


  • 你应该考虑几个无关的问题。

  • 当你可以不用锁的时候,你当然应该不用锁。当您使用多线程时,更喜欢不可变对象

  • 另一方面,不可变对象

    • 应变记忆
    • 被认为是“反OOP”
    • 可能被客户端代码错误地使用(因为人们不习惯与他们一起工作)
  • 第二种方法仍然需要一些并发处理策略,因为多个线程可能会设置具有不同启动假设的信息

  • 我不确定引用赋值是原子的。如果是,为什么CLR有
    联锁的.Exchange
    ?感谢亨克·霍特曼指出这一点


  • 你应该考虑几个无关的问题。

  • 当你可以不用锁的时候,你当然应该不用锁。当您使用多线程时,更喜欢不可变对象

  • 另一方面,不可变对象

    • 应变记忆
    • 被认为是“反OOP”
    • 可能被客户端代码错误地使用(因为人们不习惯与他们一起工作)
  • 第二种方法仍然需要一些并发处理策略,因为多个线程可能会设置具有不同启动假设的信息

  • 我不确定引用赋值是原子的。如果是,为什么CLR有
    联锁的.Exchange
    ?感谢亨克·霍特曼指出这一点


  • 为了以防万一,锁定一个
    私有静态只读对象
    ,而不是仪器信息数组-就像防御性的编码实践一样。@codesparkle-锁定一个
    静态
    对象会导致(更多)争用。当前的方法(
    ii
    不是数组)看起来还可以。@Henkholtman他正在锁定
    lock(instrumentInfos){
    这是一个数组。
    ii
    与它无关。但是你是对的,使它静态是不必要的,也是不好的。只读可以。你是对的,我正在查看另一个锁。
    锁(仪表信息)
    可能根本不需要。@HenkHolterman需要保证只创建了一个实例。如果从不同的线程调用GetInstrumentInfo,一个线程可能会获得无效的副本。当然,代码可能会被重构,所以我
    只在
    结果==null
    的情况下锁定
    private静态只读对象
    而不在您的仪表信息数组中-这只是一种防御性的编码实践。@codesparkle-锁定
    静态
    对象将导致(远远)超出必要的争用。当前的方法(
    ii
    不是数组)看起来还可以。@Henkhoterman他正在锁定
    锁(仪表信息){
    这是一个数组。
    ii
    与此无关。但是你是对的,将其设为静态是不必要的,也是不好的。只读即可。你是对的,我正在查看另一个锁。
    锁(instrumentInfos)
    可能根本不需要。@HenkHolterman需要保证只创建了一个实例。如果从不同的线程调用GetInstrumentInfo,一个线程可能会获得无效的副本。当然,代码可能会被重构,因此只有在