我应该尝试避免超低延迟软件中的“新”关键字吗?

时间:2013-01-09 17:36:38

标签: c# performance low-latency hft

我正在编写HFT交易软件。我确实关心每一微秒。现在它是用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
    }

我想超低延迟软件不应该过多使用“新”关键字,所以我将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
    }

可能我应该尽量避免使用“新”关键字?我可以使用预分配对象的一些“池”:

// 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
  • 的重要性
  • 在使用我需要配置的预分配对象时,我会赢得任何东西吗? (在上面的例子中设置类型和价格)

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

3 个答案:

答案 0 :(得分: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 ++中你必须更加关注资源管理,这是通过一种称为&#34; RAII&#34; - 这实质上意味着在分配点处理资源将如何被删除(通过对象的析构函数)。

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

  • 正确使用算法
  • 适当的并行处理和同步技术
  • 有效缓存和懒惰评估。

答案 1 :(得分:2)

尽管我厌恶HFT,但我会告诉你如何在给定的铁片上获得每个线程的最大性能。

Here's an explanation一个例子,其中最初编写的程序的速度提高了730倍。

你是分阶段完成的。在每个阶段,您都会发现需要花费大量时间的东西,并且您可以修复它。 关键字是 find ,而不是 guess 。 有太多人只关注代码,并修复他们认为有用的东西,而且往往但并非总是有帮助,有些人。 这是猜测。 要获得真正的加速,您需要找到所有问题,而不仅仅是您可以猜到的几个问题。

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

这是theory behind it

答案 2 :(得分:0)

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