simdjson-go:在Go中每秒解析千兆字节的JSON

simdjson-go:在Go中每秒解析千兆字节的JSON


介绍

JSON已将自己确立为Web的“通用语言”。因此,对于许多应用程序而言,JSON的解析性能非常重要。尽管JSON具有简单且人性化的特性,但从技术上讲,它并不是一种高速解析的琐碎格式。

最近提出了一些新设计,其中之一是Daniel Lemire和Geoff Langdale的simdjsonsimdjson使用一种新颖的两阶段方法,可以在单个内核上实现每秒千兆字节JSON的解析性能。利用所谓的SIMD指令,每个指令可以执行更多的文本和数字运算,从而显着提高性能。

在MinIO,我们一直在研究simdjson-go,它是Golang的端口。您可能知道MinIO是基于S3 API的高性能对象存储。亚马逊一直在稳步向S3 API添加功能,最近的一项添加就是名为S3 Select的功能。此功能实质上允许应用程序以JSON或CSV之类的格式向下钻取(大)blob对象的内容。这样,我们就可以使用我们可以获得的所有解析性能,因此进行这项工作对我们很有意义。

在性能方面,simdjson-go平均运行速度约为simdjson的40%至60%。与Golang的标准软件包相比encoding/jsonsimdjson-go速度提高了约10倍。

特征

simdjson-go是验证解析器,这意味着它除其他验证并检查数值,布尔值等等。因此,这些值可作为适当的intfloat64解析后的表示。

另外simdjson-go具有以下功能:

  • 没有4 GB的对象限制

  • 支持ndjson(以换行符分隔的json)

  • 正确的内存管理

  • Pure Go(无需CGO)

性能与simdjson

基于同一组JSON测试文件,下图显示了simdjson之间的比较simdjson-go(越大越好)。


pasted image 0 - 2023-04-03T162343.060.png


性能与编码/ JSON

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


image-1 (3).png


设计

simdjson-go遵循与相同的两个阶段设计simdjson在第一阶段,结构元素({,},[,] 、:和)被检测到并作为消息缓冲区中的偏移量转发到第二阶段。第二阶段构建JSON文档结构的磁带格式。

请注意,与相比simdjsonsimdjson-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上找到代码

试试看。我们欢迎任何反馈和/或贡献。


上一篇 下一篇