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)
}
posted @ 2023-06-13 21:16  janbar  阅读(63)  评论(0编辑  收藏  举报