C ++与虚拟机语言在高频融资中的表现

我认为C / C ++与C#/ Java性能问题已经被很好地践踏,这意味着我读了足够的证据表明VM语言不一定比“接近硅”语言慢。 主要是因为JIT编译器可以进行静态编译语言无法进行的优化。

不过,我最近收到一位声称基于Java的高频交易总是被C ++殴打的人的简历,并且他曾处于这种情况。

在工作现场进行快速浏览确实表明,HFT申请人需要C ++知识,并且看看Wilmott论坛可以看到所有从业人员在谈论C ++。

有这种情况的原因是什么? 我会认为,现代金融业务有些复杂,具有类型安全性,托管内存和丰富库的VM语言将是首选。 这样的生产率更高。 另外,JIT编译器越来越好。 他们可以在程序运行时进行优化,所以您会认为他们使用该运行时信息来击败非托管程序的性能。

也许这些人正在用C ++编写关键代码,并且从托管环境(P / Invoke等)调用它们? 那可能吗?

最后,有没有人有这方面的核心问题的经验,这就是为什么在这个领域的非托管代码无疑是优先于托管?

据我所知,HFT家伙需要尽可能快地对市场数据做出反应,但这并不一定是硬实时要求。 如果你很慢,你会变得更糟,这是肯定的,但是你不需要保证每个响应都有一定的速度,你只需要一个快速的平均值。

编辑

对,到目前为止有几个很好的答案,但相当一般(很好的理由)。 让我指定HFT家伙会运行什么样的程序。

主要标准是响应性。 当订单投放市场时,您希望成为第一个能够对此做出反应的公司。 如果你迟到了,别人可能会拿走它,但是每家公司都有一个略有不同的策略,所以如果一次迭代有点慢,你可能会好起来。

该程序整天运行,几乎没有用户干预。 无论处理每个新市场数据的功能是每秒运行数十次(甚至数百次)。

这些公司对硬件的价格一般没有限制。


首先,1毫秒是HFT中的永恒。 如果你认为它不是这样的话,那么多做一点关于这个领域的知识就太好了。 (就像距离交换所100英里)吞吐量和等待时间深深交织在一起,因为任何初等排队理论教科书中的公式都会告诉你。 相同的公式将显示抖动值(如果网络结构正确且未配置足够的内核,则通常由CPU队列延迟的标准偏差占主导地位)。

HFT套利存在的一个问题是,一旦你决定获得价差,有两条腿(或更多)来实现利润。 如果你没有打到所有的腿,你可能会留下一个你真正不想要的位置(以及随后的损失) - 毕竟你是套利而不是投资。

除非你的策略预测(非常近期!!!)未来(并且这一点,相信与否,非常成功),否则你不需要职位。 如果你距离交易所有1毫秒的距离,那么你的订单中的一小部分将不会被执行,你想要的将被取消。 最有可能执行一条腿的人最终会失败,或者至少没有赢利。

无论您的策略是为了争论的缘故,让我们说它赢得55%/ 45%的胜率。 即使赢/输比率发生微小变化,盈利能力也会发生重大变化。

re:“跑几十(甚至几百)”似乎没有数量级的差距即使看上去每秒钟20000个嘀嗒声似乎很低,尽管这可能是整个一天他正在看的乐器组的平均时间。

在任何给定的时间里,所看到的利率都有很大的变化。 我会举一个例子。 在我的一些测试中,我看到7个OTC股票(CSCO,GOOG,MSFT,EBAY,AAPL,INTC,DELL)在一天中每秒钟的流量可以从0 mps(非常非常罕见)到几乎将近2000次报价和每高峰时段的交易次数。 (看看为什么我认为20000以上是低的。)

我为这个领域建立了基础设施和测量软件,我们谈论的数字是每秒100000和数百万。 我有C ++生产者/消费者基础架构库,可以在生产者和消费者之间推送几乎500万(500万)条消息(32位,2.4 GHz内核)。 这些是在生产者端用新的,构造,入队,同步的 64字节消息,并且在消费者端免费地同步,出列,触摸每个字节,运行虚拟析构器 。 现在可以肯定的是,这是一个简单的基准测试,没有Socket IO(并且套接字IO可能很难看),就像在端点管道阶段的终点一样。 它是所有自定义同步类,只在空,自定义分配器,自定义锁定空闲队列和列表,偶尔STL(具有自定义分配器),但更常见自定义侵入集合(其中我有一个重要的库)时同步。 不止一次,我已经给这个舞台上的供应商提供了四倍(甚至更多)的吞吐量,而不增加套接字端点的批量。

我有OrderBook和OrderBook :: Universe类,在22000种仪器上取平均值时,新增,插入,查找,部分填充,查找,第二次填充,删除和删除顺序少于2us。 该基准在插入第一次填充和最后一次填充之间连续地遍历所有22000个仪器,因此没有涉及便宜的缓存技巧。 进入同一本书的操作通过访问22000本不同的书籍进行分隔。 这些不是真实数据的缓存特性。 实时数据在时间上更加本地化,​​连续交易经常出现在同一本书中。

所有这些工作都需要仔细考虑所使用集合的任何算法成本中的常量和缓存特征。 (有时看起来KO(n)KO(n * log n)等中的K等等被有些太过分了)

我在Marketdata基础设施方面工作。 即使想到使用java或托管环境来完成这项工作也是不可思议的。 当你用C ++获得这种表现时,我认为在托管环境下获得百万+ / mps性能是相当困难的),我无法想象任何重要的投资银行或对冲基金(为其提供25万美元的薪水一流的C ++程序员不算什么)不会用C ++。

有没有人真的从托管环境中获得2000000 + / mps的性能? 我认识这个舞台上的几个人,没有人向我吹嘘过这件事。 而且我认为2mm在托管环境中会有一些吹牛的权利。

我知道一个主要玩家的FIX命令解码器以12000000场解码/秒的速度进行。 (3Ghz CPU)这是C ++,编写它的人几乎要挑战任何人在即使速度达到一半的托管环境中提出某些东西。

从技术上讲,这是一个有趣的领域,有很多有趣的性能挑战。 当潜在的安全性变化时考虑期权市场 - 可能会有6个未完成的价格点,有3个或4个不同的到期日期。 现在每笔交易大约有10-20个报价。 这些报价可能会触发期权价格变化。 因此,对于每笔交易,期权报价可能会有100或200个变化。 这只是大量的数据 - 不是大型强子对撞机碰撞检测器的数据量,但仍然是一个挑战。 这与处理击键有点不同。

甚至关于FPGA的争论也在继续。 许多人认为在3GHZ商品硬件上运行的编码良好的解析器可以击败500MHz的FPGA。 但即使速度稍微慢一些(并不是说它们),基于FPGA的系统可能趋于具有更紧密的延迟分布。 (阅读“倾向” - 这不是一揽子声明)当然,如果你有一个伟大的C ++解析器,你通过Cfront推送,然后通过FPGA图像生成器推送它...但那另一个辩论......


很多都归结为事实与理论之间的简单差异。 人们有先进的理论来解释为什么Java应该(或者至少可能)比C ++更快。 大多数论据与Java或C ++本身无关,但是对于动态编译和静态编译而言,Java和C ++实际上仅仅是两者的示例(当然,可以静态编译Java或C ++动态)。 这些人中的大多数都有基准来“证明”他们的主张。 当仔细检查这些基准时,很快就会发现,在很多情况下,他们采取相当极端的措施来获得他们想要的结果(例如,在编译Java时可以优化数量,但在编译时特别禁用优化C ++)。

与计算机语言基准游戏比较,几乎任何人都可以提交一个条目,所以所有的代码都趋向于在合理的程度上进行优化(甚至在一些情况下甚至是不合理的程度)。 很明显,有相当数量的人将此视为本质上的竞争,每个语言的倡导者尽其最大努力“证明”他们的首选语言是最好的。 由于任何人都可以提交任何问题的执行情况,所以提交特别差的内容对整体结果影响不大。 在这种情况下,C和C ++成为明确的领导者。

更糟糕的是,如果有什么结果可能会让Java看起来比完全准确。 尤其是,使用C或C ++并真正关心性能的人可以(而且经常会)使用Intel的编译器而不是g ++。 与g ++相比,这通常会使速度至少提高20%。

编辑(回应jalf提出的几个要点,但真的太长以至于无法合理地评论):

  • 指针是优化器作家的噩梦。 这真是夸大了事情(相当)。 指针会导致混淆的可能性,这会在某些情况下阻止某些优化。 也就是说,内联可以在很长时间内防止不良影响(即,编译器可以检测是否存在别名,而不是在可能存在假设的情况下始终生成代码)。 即使代码不得不假设出现混叠,缓存也会最大限度地降低这种性能(即L1缓存中的数据仅比寄存器中的数据慢)。 防止锯齿会有助于C ++的性能,但不会达到您想象的那么高。

  • 垃圾收集器的分配要快得多。 当然,许多C ++实现中的默认分配器比大多数(当前)垃圾收集分配器提供的分配器要慢。 这是平衡的(至少在某种程度上),因为C ++中的分配倾向于在堆栈上,这也是快速的,而在GC语言中,几乎所有的分配通常都在堆上。 更糟糕的是,在托管语言中,您通常为每个对象分别分配空间,而在C ++中,通常为一个范围内的所有对象分配空间。

  • 同样,C ++直接支持在全局和逐类基础上替换分配器,所以当分配速度真的成为问题时,它通常很容易修复。

    最终,贾尔夫是正确的:这两点无疑都支持“托管”实现。 但是,改进的程度应该保持透彻:它们不足以让动态编译的实现在很多代码上运行得更快 - 甚至没有从一开始就设计的基准测试,尽可能多地支持它们。

    编辑2:我看到乔恩哈罗普试图插入他的两个十亿分之一的价值。 对于那些不认识他的人来说,乔恩多年来一直是臭名昭着的巨魔和垃圾邮件制造者,似乎正在寻找播种杂草的新领域。 我会尽量详细回复他的评论,但是(正如他的典型情况),它仅仅包含非限定的,不受支持的概括,其中包含的实际内容很少,以至于无法进行有意义的回复。 关于所有可以做的事情是让旁观者公平的警告,他以不诚实,自私而且最好被忽视而闻名。


    JIT编译器理论上可以执行很多优化,但是,您愿意等多久? 一个C ++应用程序可能需要几个小时才能编译,因为它发生在离线状态,而用户并不坐在那里轻敲手指并等待。

    JIT编译器必须在几毫秒内完成。 那么,您认为哪些可以通过最复杂的优化解决?

    垃圾收集器也是一个因素。 不是因为它比本身的手动内存管理慢(我认为它的摊销成本相当不错,绝对可以与手动内存处理相比),但它不太可预测。 它几乎可以在任何时候引入失速,这在需要非常敏感的系统中可能是不可接受的。

    当然,这些语言适合不同的优化。 C ++允许你编写非常紧凑的代码,几乎没有内存开销,并且许多高级操作基本上都是免费的(比如,类构造)。

    另一方面,在C#中,你浪费了大量的内存。 简单地实例化一个类会带来很大的开销,因为即使实际的类是空的,基类Object也必须被初始化。

    C ++允许编译器积极剥离未使用的代码。 在C#中,它大部分必须在那里,所以它可以通过反射找到。

    另一方面,C#没有指针,这是优化编译器的噩梦。 而托管语言中的内存分配远比C ++便宜。

    无论哪种方式都有其优点,所以期望您可以得到一个简单的“一个或另一个”答案是天真的。 根据确切的源代码,编译器,操作系统以及运行的硬件,其中一个或另一个可能会更快。 根据您的需求,原始绩效可能不是第一目标。 也许你对反应更感兴趣,以避免不可预知的失速。

    一般而言,您的典型C ++代码的表现与其等价的C#代码类似。 有时更快,有时更慢,但可能两者之间没有显着差异。

    但是,这又取决于具体情况。 这取决于你愿意花多少时间来优化。 如果你愿意花费尽可能多的时间,C ++代码通常可以获得比C#更好的性能。 它只需要很多工作。

    当然,另一个原因是,大多数使用C ++的公司已经拥有一个大型的C ++代码库,他们并不特别想要这样做。 即使他们逐渐将(某些)新组件迁移到托管语言,他们也需要继续工作。

    链接地址: http://www.djcxy.com/p/14971.html

    上一篇: Performance of C++ vs Virtual Machine languages in high frequency finance

    下一篇: What techniques can be used to speed up C++ compilation times?