simdjson-go:在Go中每秒解析千兆字节的JSON
介绍
JSON已将自己确立为Web的“通用语言”。因此,对于许多应用程序而言,JSON的解析性能非常重要。尽管JSON具有简单且人性化的特性,但从技术上讲,它并不是一种高速解析的琐碎格式。
最近提出了一些新设计,其中之一是Daniel Lemire和Geoff Langdale的simdjson。simdjson使用一种新颖的两阶段方法,可以在单个内核上实现每秒千兆字节JSON的解析性能。利用所谓的SIMD指令,每个指令可以执行更多的文本和数字运算,从而显着提高性能。
在MinIO,我们一直在研究simdjson-go,它是Golang的端口。您可能知道MinIO是基于S3 API的高性能对象存储。亚马逊一直在稳步向S3 API添加功能,最近的一项添加就是名为S3 Select的功能。此功能实质上允许应用程序以JSON或CSV之类的格式向下钻取(大)blob对象的内容。这样,我们就可以使用我们可以获得的所有解析性能,因此进行这项工作对我们很有意义。
在性能方面,simdjson-go平均运行速度约为simdjson的40%至60%。与Golang的标准软件包相比encoding/json,simdjson-go速度提高了约10倍。
特征
simdjson-go是验证解析器,这意味着它除其他验证并检查数值,布尔值等等。因此,这些值可作为适当的int和float64解析后的表示。
另外simdjson-go具有以下功能:
没有4 GB的对象限制
支持ndjson(以换行符分隔的json)
正确的内存管理
Pure Go(无需CGO)
性能与simdjson
基于同一组JSON测试文件,下图显示了simdjson和之间的比较simdjson-go(越大越好)。

性能与编码/ JSON
以下是encoding/json基于相同JSON测试文件集的Golang标准软件包的性能比较。

设计
simdjson-go遵循与相同的两个阶段设计simdjson。在第一阶段,结构元素({,},[,] 、:和)被检测到并作为消息缓冲区中的偏移量转发到第二阶段。第二阶段构建JSON文档结构的磁带格式。
请注意,与相比simdjson,simdjson-go输出uint32增加到第二级(与绝对值相反)。这允许解析任意大的JSON文件(只要单个(字符串)元素不超过4 GB ...)。
同样,为了获得更好的性能,两个阶段都作为单独的go例程同时运行,并且使用go通道在两个阶段之间进行通信。
阶段1
阶段1已使用c2goasm从原始C代码(包含SIMD内部函数)转换为Golang程序集。它包含五个单独的步骤:
find_odd_backslash_sequences:检测用于转义引号的反斜杠字符find_quote_mask_and_bits:生成带引号之间的字符的位打开的掩码find_whitespace_and_structurals:为空格生成掩码,为结构字符生成掩码finalize_structurals:将上面计算出的掩码组合成最终掩码,其中每个有效位代表输入消息中结构字符的位置。flatten_bits_incremental:输出最终掩码中的有效位作为增量偏移量。
有一个最后的例程,find_structural_bits_in_slice将其绑定在一起,并使用消息缓冲区的一部分进行调用,以查找增量偏移量。
第二阶段
在阶段2中,将构建磁带结构。本质上,它是一个单一函数,它在查找各种结构特征并构建其遇到的JSON文档的层次结构时会跳来跳去。JSON元素的值(例如字符串,整数,布尔值等)将被解析并写入磁带。
用法和要求
成功解析JSON内容后,simdjson-go将返回一个迭代器以浏览磁带结构。这是一个如何遍历
for {
typ := iter.Advance()
switch typ {
case simdjson.TypeRoot:
if typ, tmp, err = iter.Root(tmp); err != nil {
return
}
if typ == simdjson.TypeObject {
if obj, err = tmp.Object(obj); err != nil {
return
}
e := obj.FindKey(key, &elem)
if e != nil && elem.Type == simdjson.TypeString {
v, _ := elem.Iter.StringBytes()
fmt.Println(string(v))
}
}
default:
return
}
}根据要求,simdjson-go需要同时支持AVX2和CLMUL的CPU。
结论
simdjson-go是开源的,并根据Apache License v2.0发布。您可以在github.com/minio/simdjson-go下的Github上找到代码。
试试看。我们欢迎任何反馈和/或贡献。