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

时间:2012-06-23 08:37:51

标签: c#

我正在编写HFT交易软件。我正在尝试优化它。我发现每一秒我创建了几千个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个。但是我每秒都会多次创建相同的Instrument对象,如下所示:

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

即。我有很多“MSFT”工具的实例,但我可以在HashSet / HashMap中使用它们,或者由于覆盖EqualsGetHashCode方法而使用它们。

但是现在我想如果在运行时10或100“MSFT”Instrument对象(彼此相等)是有意义的。

所以我想创建类似的东西:

interface InstrumentFactory {

    public Instrument GetInstrument(int GateId, string Ticker);

}

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

问题:

  • 采用新方法,我会有明显的性能提升吗?
  • 你对新设计有什么看法?当我经常需要相同的对象时,最好使用factory而不是每次使用覆盖的Equals和GetHashCode方法创建新对象?

2 个答案:

答案 0 :(得分:2)

您目前无法缓存这些内容,因为它们是可变的 - TickerGateID都有公共制定者。

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

此时,它是一个更好的类无论如何 IMO(它更容易推理不可变类型)并且缓存值是完全合理的。它会使你的应用程序明显加快吗?我们不可能告诉你 - 但你应该能够,假设你已经进行了性能测试。这样做至少是有道理的。

编辑:请注意,您不仅可以在工厂中使用HashSet。你可能想要像Dictionary<int, Dictionary<string, Instrument>>这样的东西 - 从第一本字典中查找门,然后从门进入仪器。如果你有一个从0开始的已知固定数量的门,你甚至可能想要使用一个数组。您还应该考虑创建Gate类型。

使用Dictionary.TryGetValue检查门内是否存在门或仪器,然后添加懒惰创建门/仪器并将其放入字典中(如果以前不存在)。

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

答案 1 :(得分:1)

如果你只有100个不同的对象,但是你需要数以千计的实例,那么工厂可能是一种方法,但是在你有一些改变构造的策略之前,性能不会改变。想到原型模式,但这些对象似乎很容易创建,因此性能不会受到影响。也许一些对象池可以是一个解决方案。预先创建您需要的大量对象,并将实例从池中取出。让你的对象是不可变的,这是先决条件。有一个游泳池,你可以轻松获得物品,如果你不再需要它们,只需将它们放回池中即可。

以下是关于对象池的一些想法: CodeProject on object pooling