我正在编写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中使用它们,或者由于覆盖Equals
和GetHashCode
方法而使用它们。
但是现在我想如果在运行时10或100“MSFT”Instrument
对象(彼此相等)是有意义的。
所以我想创建类似的东西:
interface InstrumentFactory {
public Instrument GetInstrument(int GateId, string Ticker);
}
每次我需要一些乐器时,我只想询问InstrumentFactory。 InstrumentFactory将在内部将我的100个乐器存储在HashSet中,只返回缓存副本。此外,我现在可以删除Equals
和GetHashCode
方法,因为每个gateId +代码对只有一个Instrument
。
问题:
factory
而不是每次使用覆盖的Equals和GetHashCode方法创建新对象?答案 0 :(得分:2)
您目前无法缓存这些内容,因为它们是可变的 - Ticker
和GateID
都有公共制定者。
我会使它不可变(并密封类),但可能会保留Equals
和GetHashCode
方法。添加构造函数以获取参数,而不是将它们设置为属性。
此时,它是一个更好的类无论如何 IMO(它更容易推理不可变类型)并且缓存值是完全合理的。它会使你的应用程序明显加快吗?我们不可能告诉你 - 但你应该能够,假设你已经进行了性能测试。这样做至少是有道理的。
编辑:请注意,您不仅可以在工厂中使用HashSet
。你可能想要像Dictionary<int, Dictionary<string, Instrument>>
这样的东西 - 从第一本字典中查找门,然后从门进入仪器。如果你有一个从0开始的已知固定数量的门,你甚至可能想要使用一个数组。您还应该考虑创建Gate
类型。
使用Dictionary.TryGetValue
检查门内是否存在门或仪器,然后添加懒惰创建门/仪器并将其放入字典中(如果以前不存在)。
如果您在单个工厂中使用多个线程,则需要 使用锁定,或者如果您使用的是.NET 4,则可以使用ConcurrentDictionary
。当然,这是假设你不知道所有的仪器。如果你做在你开始之前知道所有事情,这很容易 - 只需填写工厂开始,如果你被要求提供一个不存在的工具,就抛出异常。
答案 1 :(得分:1)
如果你只有100个不同的对象,但是你需要数以千计的实例,那么工厂可能是一种方法,但是在你有一些改变构造的策略之前,性能不会改变。想到原型模式,但这些对象似乎很容易创建,因此性能不会受到影响。也许一些对象池可以是一个解决方案。预先创建您需要的大量对象,并将实例从池中取出。让你的对象是不可变的,这是先决条件。有一个游泳池,你可以轻松获得物品,如果你不再需要它们,只需将它们放回池中即可。
以下是关于对象池的一些想法: CodeProject on object pooling