C# 我应该缓存使用密集型的简单类吗?

C# 我应该缓存使用密集型的简单类吗?,c#,C#,我在写高频交易软件。我正在尝试优化它。我发现每秒钟我都会创建数千个Instrument对象,这个类的源代码如下: public class Instrument { public int GateId { get; set; } public string Ticker { get; set; } public override string ToString() { return "GateID: " + GateId + " Ticker:

我在写高频交易软件。我正在尝试优化它。我发现每秒钟我都会创建数千个
Instrument
对象,这个类的源代码如下:

public class Instrument
{

    public int GateId { get; set; }
    public string Ticker { get; set; }
    public override string ToString()
    {
        return "GateID: " + GateId + " Ticker: " + Ticker + '.';
    }

    public override bool Equals(object obj)
    {
        if (obj == null)
        {
            return false;
        }
        Instrument instrument = obj as Instrument;
        if (instrument == null)
        {
            return false;
        }
        return (GateId.Equals(instrument.GateId)) && (Ticker.Equals(instrument.Ticker));
    }

    public override int GetHashCode()
    {
        int hash = 13;
        hash = (hash * 7) + GateId;
        hash = (hash * 7) + Ticker.GetHashCode();
        return hash;
    }
}
仪器的实际数量非常有限。总共大约100英镑。但我一直在每秒多次创建相同的仪器对象,如下所示:

new Instrument { GateId = 0, Ticker = "MSFT" }
interface InstrumentFactory {

    public Instrument GetInstrument(int GateId, string Ticker);

}
也就是说,我有许多“MSFT”工具的实例,但由于覆盖了
Equals
GetHashCode
方法,我可以在HashSet/HashMap或任何地方使用它们

但现在我认为在运行时使用10或100“MSFT”
Instrument
对象(它们彼此相等)是否有意义

所以我想创造这样的东西:

new Instrument { GateId = 0, Ticker = "MSFT" }
interface InstrumentFactory {

    public Instrument GetInstrument(int GateId, string Ticker);

}
每次我需要一些仪器时,我只想问问仪器厂。InstrumentFactory将在内部将我的100个仪器存储在HashSet中,并返回缓存副本。此外,我现在可以删除
Equals
GetHashCode
方法,因为对于每个gateId+股票代码对,我只有一个
Instrument

问题:

  • 有了新的方法,我会有显著的性能改进吗
  • 你觉得新设计怎么样?当我经常需要相同的对象时,是否最好使用
    factory
    ,而不是每次使用重写的Equals和GetHashCode方法创建新对象

您当前无法缓存这些,因为它们是可变的,
Ticker
GateID
具有公共设置器

我将使其不可变(并密封该类),但可能保留
Equals
GetHashCode
方法。添加构造函数以获取参数,而不是将其设置为属性

在这一点上,它是一个更好的类(更容易对不可变类型进行推理),并且缓存值是完全合理的。它会使您的应用程序明显更快吗?我们不可能这么说,但假设您已经进行了性能测试,您应该能够这么说。至少这样做是有道理的

编辑:请注意,您不仅能够在工厂中使用
HashSet
。您可能需要类似于
字典的东西
——从第一本字典中查找gate,然后从gate中查找instrument。如果已知固定数量的门从0开始,则可能需要使用数组。您还应该考虑创建<代码>门< /代码>类型。

使用
Dictionary.TryGetValue
检查闸门内是否存在闸门或仪器,然后添加,然后懒洋洋地创建闸门/仪器,如果之前不存在,则将其放入字典中


如果在单个工厂中使用多个线程,则需要使用锁定,或者如果使用.NET 4,则可以使用
ConcurrentDictionary
。当然,这是假设你不知道前面所有的仪器。如果你在开始之前就知道了一切,那就很容易了——只要填充工厂就可以开始了,如果你被要求使用一个不存在的仪器,就会抛出一个异常。

你现在不能缓存这些,因为它们是可变的,
股票代码
GateID
都有公共设置器

我将使其不可变(并密封该类),但可能保留
Equals
GetHashCode
方法。添加构造函数以获取参数,而不是将其设置为属性

在这一点上,它是一个更好的类(更容易对不可变类型进行推理),并且缓存值是完全合理的。它会使您的应用程序明显更快吗?我们不可能这么说,但假设您已经进行了性能测试,您应该能够这么说。至少这样做是有道理的

编辑:请注意,您不仅能够在工厂中使用
HashSet
。您可能需要类似于
字典的东西
——从第一本字典中查找gate,然后从gate中查找instrument。如果已知固定数量的门从0开始,则可能需要使用数组。您还应该考虑创建<代码>门< /代码>类型。

使用
Dictionary.TryGetValue
检查闸门内是否存在闸门或仪器,然后添加,然后懒洋洋地创建闸门/仪器,如果之前不存在,则将其放入字典中


如果在单个工厂中使用多个线程,则需要使用锁定,或者如果使用.NET 4,则可以使用
ConcurrentDictionary
。当然,这是假设你不知道前面所有的仪器。如果你在开始之前就知道了一切,那么这真的很容易——只要填充工厂就可以了,如果你需要一个不存在的仪器,就会抛出一个异常。

如果你只有100个不同的对象,但你需要数千个这样的实例,那么工厂可能是一个不错的选择,但是,除非你有一些策略来改变建筑的某些方面,否则性能不会改变。我们想到了原型模式,但这些对象似乎很容易创建,因此性能不会受到影响。也许某个对象池可以是一个解决方案。预先创建大量您需要的对象,并从池中取出实例。让你的对象是不可变的,这是先决条件。拥有一个池,您可以轻松获得对象,如果不再需要它们,只需将它们放回池中即可

以下是关于对象池的一些想法:

如果您只有100个不同的对象,但您需要数千个这些对象的实例,那么工厂可能是一条出路,但性能不会改变,除非您有一些策略来改变有关构造的内容。我们想到了原型模式,但这些对象似乎很容易创建,因此性能不会受到影响。也许某个对象池可以是一个解决方案。预处理批次o