golang对于[]byte数组转string进行比较的优化
当需要比较两个[]byte
数组是否相等时有好几种方案,下面可以看出前三种方案都是优化过的,效率高的方案。
package main
import (
"bytes"
"crypto/rand"
mr "math/rand"
"testing"
)
func StringEqual(n int, f func(a, b []byte) bool) {
buf := make([]byte, 1024)
rand.Read(buf)
var total int
for i := 0; i < n; i++ {
start1 := mr.Intn(len(buf))
len1 := mr.Intn(len(buf) - start1)
start2 := mr.Intn(len(buf))
len2 := mr.Intn(len(buf) - start2)
if f(buf[start1:start1+len1], buf[start2:start2+len2]) {
total++
}
}
}
func BenchmarkStringCompare(b *testing.B) {
StringEqual(b.N, func(a, b []byte) bool {
return bytes.Compare(a, b) == 0
})
}
func BenchmarkStringCompare1(b *testing.B) {
StringEqual(b.N, func(a, b []byte) bool {
return string(a) == string(b)
})
}
func BenchmarkStringEqual(b *testing.B) {
StringEqual(b.N, func(a, b []byte) bool {
return bytes.Equal(a, b)
})
}
func BenchmarkStringCompare2(b *testing.B) {
StringEqual(b.N, func(a, b []byte) bool {
sa := string(a)
sb := string(b)
return sa == sb
})
}
下面是结果,所以用bytes.Equal(a, b)
属于好理解且效率高的方案
# go test -v -bench=.
goos: windows
goarch: amd64
pkg: janbar/test1
cpu: Intel(R) Core(TM) i7-10875H CPU @ 2.30GHz
BenchmarkStringCompare
BenchmarkStringCompare-16 19283643 66.46 ns/op
BenchmarkStringCompare1
BenchmarkStringCompare1-16 17937969 64.16 ns/op
BenchmarkStringEqual
BenchmarkStringEqual-16 20451116 63.72 ns/op
BenchmarkStringCompare2
BenchmarkStringCompare2-16 7030708 181.5 ns/op
PASS
ok janbar/test1 5.462s
源码也说了不会有额外的内存分配,该方案应该是结合if
语句一起优化的
// Equal reports whether a and b
// are the same length and contain the same bytes.
// A nil argument is equivalent to an empty slice.
func Equal(a, b []byte) bool {
// Neither cmd/compile nor gccgo allocates for these string conversions.
return string(a) == string(b)
}