2

我正在编写高频交易软件。我确实关心每一微秒。现在它是用 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
  • 使用我只需要配置的预分配对象时,我会赢得什么吗?(在上面的示例中设置类型和价格)

请注意,这是超低延迟,所以让我们假设性能优于可读性、可维护性等。

4

3 回答 3

4

在 C++ 中,您不需要new创建范围有限的对象。

void FrequentlyCalledMethod() 
{
    std::vector<Action> actions;
    actions.reserve( 10 );
    for (int i = 0; i < 10; i++) 
    {
        actions.push_back( Action(....) );
    }
    // use actions, synchronous
    executor.Execute(actions);
    // now actions can be deleted
}

如果Action是基类并且您拥有的实际类型是派生类,您将需要一个指针或智能指针和new此处。但是如果 Action 是一个具体的类型并且所有元素都将是这种类型,并且这种类型是默认可构造的、可复制的和可分配的,则不需要。

但总的来说,您的性能优势不太可能来自不使用新的。在 C++ 中,当它是对象的范围时,使用局部函数范围是一种很好的做法。这是因为在 C++ 中,您必须更多地关注资源管理,这是通过一种称为“RAII”的技术完成的——这本质上意味着关注如何删除资源(通过对象的析构函数)分配点。

高性能更有可能通过以下方式实现:

  • 正确使用算法
  • 适当的并行处理和同步技术
  • 有效的缓存和惰性评估。
于 2013-01-09T17:49:26.583 回答
2

尽管我很讨厌高频交易,但我将告诉你如何在给定的铁块上从每个线程中获得最大的性能。

这是一个示例的解释,其中最初编写的程序速度提高了 730 倍。

你分阶段进行。在每个阶段,您都会发现需要花费大量时间的东西,然后将其修复。关键字是find,而不是guess。太多的人只是盯着代码,然后修复他们认为有帮助的东西,而且通常但并不总是有帮助,有些人。那是猜测。要获得真正的加速,您需要找到所有问题,而不仅仅是您能猜到的少数问题。

如果您的程序正在执行new,那么很有可能在某些时候这将是您需要修复的。但这不是唯一的事情。

这是它背后的理论

于 2013-01-09T18:46:00.843 回答
0

对于优秀 HFT 商店的高性能交易引擎,避免在 C++ 代码中使用 new/malloc 是基本要求。

于 2014-01-29T15:55:31.453 回答