字符串与字节数组,性能

2022-09-04 20:27:57

(这篇文章是关于高频类型编程的)

我最近在一个论坛上看到(我认为他们正在讨论Java),如果你必须解析大量的字符串数据,那么使用字节数组比使用带有split()的字符串更好。确切的帖子是:

使用任何语言(C++,Java,C#)的一个性能技巧是避免创建对象。这不是分配或GC的成本,而是访问不适合CPU缓存的大型内存阵列的成本。

现代CPU比他们的内存快得多。它们会为每个缓存未命中停顿很多很多个周期。大部分 CPU 事务器预算用于通过大型缓存和大量刻度来减少这种情况。

GPU通过准备执行大量线程来隐藏内存访问延迟,并且很少或没有缓存并将晶体管花费在更多内核上,从而以不同的方式解决了这个问题。

因此,例如,与其使用 String 和 split 来解析消息,不如使用可以就地更新的字节数组。您确实希望避免对大型数据结构的随机内存访问,至少在内部循环中是这样。

他只是在说“不要使用字符串,因为它们是一个对象,创建对象是昂贵的”?还是他在说别的什么?

使用字节数组是否确保数据尽可能长时间地保留在缓存中?当您使用字符串时,它是否太大而无法保存在CPU缓存中?通常,使用基元数据类型是编写更快代码的最佳方法吗?


答案 1

他说,如果将块文本分解为单独的字符串对象,则这些字符串对象的局部性比大型文本数组差。每个字符串及其包含的字符数组都将位于内存中的其他位置;它们可以遍布各地。在处理数据时,内存缓存可能必须进出才能访问各种字符串。相比之下,一个大型数组具有最佳位置,因为所有数据都在一个内存区域上,并且缓存抖动将保持在最低限度。

当然,这有限制:如果文本非常非常大,并且您只需要解析其中的一部分,那么这几个小字符串可能比大块文本更适合缓存。


答案 2

对于 HFT,还有很多其他原因需要使用 或 代替 Strings。字符串在 Java 中由 16 位组成,并且是不可变的。 或者很容易回收,具有良好的缓存位置,可以离堆(直接)保存副本,避免字符编码器。这一切都假定您使用的是 ASCII 数据。byte[]char*charbyte[]ByteBuffer

char*或者 ByteBuffers 也可以映射到网络适配器以保存另一个副本。(对 ByteBuffers 进行一些摆弄)

在高频交易中,您很少同时处理大量数据。理想情况下,您希望在数据从套接字下来后立即对其进行处理。即一次一个数据包。(约 1.5 KB)