golang 中将 string 转换为 byte 切片,能够应用规范转换方法,也能够通过强转形式。两种形式的后果一样,然而执行效率差异很大。如下是我的两种转化形式,效率比规范的转换高很多。
在贴代码前,先理解一下 string 和 slice 的 Header 定义
StringHeader 如下,他是 string 的底层实现
type StringHeader struct {
Data uintptr
Len int
}
SliceHeader 如下
type SliceHeader struct {
Data uintptr
Len int
Cap int
}
能够发现这两个十分类似
其实就十分好了解了
Data 指向理论内容的数组
Len 长度
那么咱们就能够开始如下两种操作
- 将 StringHeader 中的 Data 赋值给 SliceHeader 的 Data
将 StringHeader 中的 Len 赋值给 SliceHeader 的 Len - 也能够间接将 StringHeader 强转成 SliceHeader(因为各个 fields 的长度和程序都是一样的)
上面间接上代码
func string2BytesSlicePlus(str string) []byte {bytesSlice := []byte{} // 此处定义了一个空切片
stringData := &(*(*reflect.StringHeader)(unsafe.Pointer(&str))).Data// 获得 StringHeader 的 Data 地址
byteSliceData := &(*(*reflect.SliceHeader)(unsafe.Pointer(&bytesSlice))).Data // 获得 SliceHeader 的 Data 地址
*byteSliceData = *stringData // 将 StringHeader.Data 的值赋给 SliceHeader.Data
(*(*reflect.SliceHeader)(unsafe.Pointer(&bytesSlice))).Len = (*(*reflect.StringHeader)(unsafe.Pointer(&str))).Len // 设置长度
return bytesSlice
}
间接强转
func string2BytesSlicePlus2(str string) []byte {strSliceHeader := *(*reflect.StringHeader)(unsafe.Pointer(&str))
byteSlice := *(*[]byte)(unsafe.Pointer(&strSliceHeader))
return byteSlice
}
const (TOTALCNT = 1000000)
func string2BytesSlicePlus(str string) []byte {bytesSlice := []byte{}
stringData := &(*(*reflect.StringHeader)(unsafe.Pointer(&str))).Data
byteSliceData := &(*(*reflect.SliceHeader)(unsafe.Pointer(&bytesSlice))).Data
*byteSliceData = *stringData
(*(*reflect.SliceHeader)(unsafe.Pointer(&bytesSlice))).Len = (*(*reflect.StringHeader)(unsafe.Pointer(&str))).Len
return bytesSlice
}
func string2BytesSlicePlus2(str string) []byte {strSliceHeader := *(*reflect.StringHeader)(unsafe.Pointer(&str))
byteSlice := *(*[]byte)(unsafe.Pointer(&strSliceHeader))
return byteSlice
}
func normalString2BytesSlice(str string) []byte {return []byte(str)
}
func TestStringConvert(t *testing.T) {
origStr := "String convert test"
convSlice := string2BytesSlicePlus(origStr)
byteSlice := []byte(origStr)
if !bytes.Equal(convSlice, byteSlice) {t.Fail()
}
convSlice = string2BytesSlicePlus2(origStr)
if !bytes.Equal(convSlice, byteSlice) {t.Fail()
}
}
//Run go test -bench="." -benchmem to verify efficiency
func Benchmark_NormalConvert(t *testing.B) {
for count := 0; count < TOTALCNT; count++ {
str := "This is string to byte slice convert test!!!"
_ = normalString2BytesSlice(str)
}
}
func Benchmark_PlusConvert(t *testing.B) {
for count := 0; count < TOTALCNT; count++ {
str := "This is string to byte slice convert test!!!"
_ = string2BytesSlicePlus(str)
}
}
func Benchmark_PlusConvert2(t *testing.B) {
for count := 0; count < TOTALCNT; count++ {
str := "This is string to byte slice convert test!!!"
_ = string2BytesSlicePlus2(str)
}
}
执行测试
go test -bench="." -benchmem
测试后果
cpu: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
Benchmark_NormalConvert-12 1000000000 0.03040 ns/op 0 B/op 0 allocs/op
Benchmark_PlusConvert-12 1000000000 0.0002572 ns/op 0 B/op 0 allocs/op
Benchmark_PlusConvert2-12 1000000000 0.0002586 ns/op 0 B/op 0 allocs/op
PASS
ok jianghu.com/godemo/000Tips/T0018/test 0.315s
依据后果能够看出
应用规范办法 []byte(str) 转换的效率最低
应用自定义的两种办法简直无差别,效率要高很多百倍的效率差异