本文通过Go语言开源社区在ARM64平台对通用字符串比较的优化方案,向读者介绍如何通过SIMD并行化技术提升软件的执行速度。摘自OptimizeLab: https://github.com/OptimizeLab/docs
作者:surechen
SIMD即单指令多数据流(Single Instruction Multiple Data)指令集,是通过一条指令同时对多个数据进行运算的硬件加速技术,能够有效提高CPU的运算速度,主要适用于计算密集型、数据相关性小的多媒体、数学计算、人工智能等领域。
Go语言是一种快速、静态类型的开源语言,可以用来轻松构建简单、可靠、高效的软件。目前已经包括丰富的基础库如数学库、加解密库、图像库、编解码等等,其中对于性能要求较高且编译器目前还不能优化的场景,Go语言通过在底层使用汇编技术进行了优化,其中最重要的就是SIMD技术。
1. 字符串比较的性能问题
先看一个常见的问题,在各行各业的服务系统中,用户登录需要验证用户名或ID,订购货物需要对比货物ID,出行需要验证票号等等,这些都离不开字符串比较操作,字符串实际上就是字节数组,在Go语言中可以表示成[]byte的形式,字符串的比较即两个数组中对应byte的比较。因此可以直观的写出如下的比较函数代码:
func EqualBytes(a, b []byte) bool {
if len(a) != len(b) { //长度不等则返回false
return false
}
for i, _ := range a {
if a[i] != b[i] { //按顺序比较数组a和数组b中的每个byte
return false
}
}
return true
}
似乎看起来还不错,逻辑没有问题,但是这样的实现就够了吗?是否能满足所有的使用场景呢?本文通过性能测试来给出答案。通过Go benchmark进行测试得出如下数据:
用例名|用例含义|执行测试数量|每操作耗时 time/op|单位时间处理数据量
BenchmarkEqual/0-8 | 在8核下比较0B字符串 | 330669548 | 3.64 ns/op | |
BenchmarkEqual/1-8 | 在8核下比较1B字符串 | 227632882 | 5.27 ns/op | 189.74 MB/s |
BenchmarkEqual/6-8 | 在8核下比较6B字符串 | 132229749 | 9.09 ns/op | 660.35 MB/s |
BenchmarkEqual/9-8 | 在8核下比较9B字符串 | 100000000 | 10.1 ns/op | 893.80 MB/s |
BenchmarkEqual/15-8 | 在8核下比较15B字符串 | 83173801 | 14.4 ns/op | 1041.32 MB/s |
BenchmarkEqual/16-8 | 在8核下比较16B字符串 | 79955283 | 15.0 ns/op | 1069.79 MB/s |
BenchmarkEqual/20-8 | 在8核下比较20B字符串 | 67353938 | 17.8 ns/op | 1124.26 MB/s |
BenchmarkEqual/32-8 | 在8核下比较32B字符串 |