【发布时间】:2013-01-09 17:36:38
【问题描述】:
我正在编写高频交易软件。我确实关心每一微秒。现在它是用 C# 编写的,但我很快就会迁移到 C++。
让我们考虑这样的代码
// Original
class Foo {
....
// method is called from one thread only so no need to be thread-safe
public void FrequentlyCalledMethod() {
var actions = new List<Action>();
for (int i = 0; i < 10; i++) {
actions.Add(new Action(....));
}
// use actions, synchronous
executor.Execute(actions);
// now actions can be deleted
}
我觉得超低延迟的软件不应该过多的使用“new”关键字,所以我把actions移成了一个字段:
// Version 1
class Foo {
....
private List<Action> actions = new List<Action>();
// method is called from one thread only so no need to be thread-safe
public void FrequentlyCalledMethod() {
actions.Clear()
for (int i = 0; i < 10; i++) {
actions.Add(new Action { type = ActionType.AddOrder; price = 100 + i; });
}
// use actions, synchronous
executor.Execute(actions);
// now actions can be deleted
}
也许我应该尽量避免使用“new”关键字?我可以使用一些预分配对象的“池”:
// Version 2
class Foo {
....
private List<Action> actions = new List<Action>();
private Action[] actionPool = new Action[10];
// method is called from one thread only so no need to be thread-safe
public void FrequentlyCalledMethod() {
actions.Clear()
for (int i = 0; i < 10; i++) {
var action = actionsPool[i];
action.type = ActionType.AddOrder;
action.price = 100 + i;
actions.Add(action);
}
// use actions, synchronous
executor.Execute(actions);
// now actions can be deleted
}
- 我应该走多远?
- 避免
new有多重要? - 在使用我只需要配置的预分配对象时,我会赢得什么吗? (在上面的示例中设置类型和价格)
请注意,这是超低延迟,因此我们假设性能优先于可读性、可维护性等。
【问题讨论】:
-
如果这很重要,你会信任谁:互联网上的人,还是科学基准?
-
@delnan 我确实信任 stackoverflow 上的人 :)
-
我会尝试两者并进行测量。
-
请不要相信 SO 这种事情哈哈,但在我们的金融应用程序中,我们基本上预先分配了大块内存,编写了一个自定义的“内存管理器”,并“分配了”我们在这个空间中的新对象。
-
请记住,在 C# 中分配新对象的成本非常。 GC 在内存中有一个指向堆的空闲部分的指针,它将指针向上移动您分配的大小,然后运行构造函数。垃圾收集和碎片整理使堆对象比使用堆栈内存更昂贵,但是分配对象时并没有花费时间,而是稍后花费。如果这个确切的时刻对时间非常敏感,但将来某个时候会有空闲时间(运行集合),那么您可能没有问题。在 C++ 中,情况正好相反。
标签: c# performance low-latency hft