之前做了实验,[]byte类型使用string()进行转换的时候,会产生拷贝。see: 【小测试】golang中使用string()来转换[]byte数组产生了拷贝
不过今天又有了新的认识。请先看下面的benchmark测试:
// goos: windows
// goarch: amd64
// pkg: git.woa.com/ahfuzhang/go_proxy/internal
// cpu: Intel(R) Core(TM) i7-7700 CPU @ 3.60GHz
// BenchmarkStringCompare
// BenchmarkStringCompare-8 15305848 73.45 ns/op
func BenchmarkStringCompare(b *testing.B) {
buf := make([]byte, 1024)
for i := 0; i < cap(buf); i++ {
buf[i] = byte(rand.Intn(125-32) + 32)
}
total := 0
for n := 0; n < b.N; n++ {
start1 := rand.Intn(len(buf))
len1 := rand.Intn(len(buf) - start1)
start2 := rand.Intn(len(buf))
len2 := rand.Intn(len(buf) - start2)
if bytes.Compare(buf[start1:start1+len1], buf[start2:start2+len2]) == 0 {
total++
}
}
}
// goos: windows
// goarch: amd64
// pkg: git.woa.com/ahfuzhang/go_proxy/internal
// cpu: Intel(R) Core(TM) i7-7700 CPU @ 3.60GHz
// BenchmarkStringCompare1
// BenchmarkStringCompare1-8 16340803 69.47 ns/op
func BenchmarkStringCompare1(b *testing.B) {
buf := make([]byte, 1024)
for i := 0; i < cap(buf); i++ {
buf[i] = byte(rand.Intn(125-32) + 32)
}
total := 0
for n := 0; n < b.N; n++ {
start1 := rand.Intn(len(buf))
len1 := rand.Intn(len(buf) - start1)
start2 := rand.Intn(len(buf))
len2 := rand.Intn(len(buf) - start2)
if string(buf[start1:start1+len1]) == string(buf[start2:start2+len2]) {
total++
}
}
}
// goos: windows
// goarch: amd64
// pkg: git.woa.com/ahfuzhang/go_proxy/internal
// cpu: Intel(R) Core(TM) i7-7700 CPU @ 3.60GHz
// BenchmarkStringCompare2
// BenchmarkStringCompare2-8 4692843 263.5 ns/op
func BenchmarkStringCompare2(b *testing.B) {
buf := make([]byte, 1024)
for i := 0; i < cap(buf); i++ {
buf[i] = byte(rand.Intn(125-32) + 32)
}
total := 0
for n := 0; n < b.N; n++ {
start1 := rand.Intn(len(buf))
len1 := rand.Intn(len(buf) - start1)
start2 := rand.Intn(len(buf))
len2 := rand.Intn(len(buf) - start2)
s1 := string(buf[start1 : start1+len1])
s2 := string(buf[start2 : start2+len2])
if s1 == s2 {
total++
}
}
}
同样是字符串的==比较,在if中直接转换,对于转换赋值后再比较,性能相差几倍。
golang官方库的源码也看到了类似的注释:
//C:\Go\src\bytes\bytes.go
// 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)
}
看来是编译器对if语句这里的比较做了特殊优化。