在 golang 中,我们经常需要对 []byte 和 string 进行转换,比如读写文件、处理网络数据、编码解码等场景。通常情况下,这不会成为系统的性能瓶颈,但是在某些极致情况下,也可能成为拖慢性能的关键因素。那么,如何选择合适的转换方式,以达到最快的速度呢?一、标准转换标准转换是最简单也最常用的转换方式,就是使用 []byte(s) 和 string(b) 这样的语法来进行转换,其中 s 是一个字符串,b 是一个字节切片。这种方式的优点是语法简洁,易于理解,而且可以保证类型安全和数据不变性。但是,这种方式的缺点是可能会涉及内存分配和复制操作,因为字符串在 golang 中是不可变的,所以每次转换都会创建一个新的数据。package mainimport ( "testing")// 测试标准转换 string() 性能func Benchmark_NormalBytes2String(b *testing.B) { x := []byte("Hello Gopher! Hello Gopher! Hello Gopher!") for i := 0; i < b.N; i++ {  _ = string(x) }}// 测试标准转换 []byte 性能func Benchmark_NormalString2Bytes(b *testing.B) { x := "Hello Gopher! Hello Gopher! Hello Gopher!" for i := 0; i < b.N; i++ {  _ = []byte(x) }}运行 go test -bench="." -benchmem ,得到以下结果:goos: darwingoarch: amd64pkg: example/standardBenchmark_NormalBytes2String-8          83988709                13.60 ns/op           48 B/op          1 allocs/opBenchmark_NormalString2Bytes-8          73114815                16.39 ns/op           48 B/op          1 allocs/opPASSok   example/standard 3.170s可以看到,标准转换每次操作都会分配 48 字节的内存,并且耗时在 15 纳秒左右。二、强制转换强制转换是一种使用 unsafe 和 reflect 包来直接操作底层的数据结构的转换方式,这种方式可以避免内存分配和复制操作,从而提高性能。但是,这种方式的缺点是可能会破坏类型安全和数据不变性,因为它会直接修改原始数据的指针和长度信息,所以需要谨慎使用,并且遵守一些规则,比如不要修改原始数据、不要超出原始数据的范围、不要让原始数据被垃圾回收等。我们可以通过以下代码来实现强制转换,并测试它的性能:package mainimport ( "bytes" "reflect" "testing" "unsafe")// 强制转换 string 到 []bytefunc String2Bytes(s string) []byte { sh := (*reflect.StringHeader)(unsafe.Pointer(&s)) bh := reflect.SliceHeader{  Data: sh.Data,  Len:  sh.Len,  Cap:  sh.Len, } return *(*[]byte)(unsafe.Pointer(&bh))}// 强制转换 []byte 到 stringfunc Bytes2String(b []byte) string { return *(*string)(unsafe.Pointer(&b))}// 测试强制转换 string() 性能func Benchmark_Byte2String(b *testing.B) { x := []byte("Hello Gopher! Hello Gopher! Hello Gopher!") for i := 0; i < b.N; i++ {  _ = Bytes2String(x) }}// 测试强制转换 []byte 性能func Benchmark_String2Bytes(b *testing.B) { x := "Hello Gopher! Hello Gopher! Hello Gopher!" for i := 0; i < b.N; i++ {  _ = String2Bytes(x) }}运行 go test -bench="." -benchmem ,得到以下结果:goos: darwingoarch: amd64pkg: example/forceBenchmark_Byte2String-8                 1000000000               0.3156 ns/op          0 B/op          0 allocs/opBenchmark_String2Bytes-8                1000000000               0.3137 ns/op          0 B/op          0 allocs/opPASSok   example/force 1.586s可以看到,强制转换每次操作都不会分配内存,并且耗时在 1 纳秒以下,性能明显优于标准转换。三、拼接转换拼接转换是一种使用 strings.Builder 或 bytes.Buffer 来拼接字符串或字节切片的转换方式。通常只有一个字符串或者字节切片,我们并不会选择这种方式来进行转换,因为这会增加操作步骤,性能不会太高。但是如果我们有很多字符串或者字节切片需要拼接并转换,这或许是一种方式。这种方式可以减少内存分配的次数,提高性能。我们可以通过以下代码来实现拼接转换,并测试它的性能:package mainimport ( "bytes" "strings" "testing")// 拼接转换 string 到 []bytefunc StringJoinBytes(s string) []byte { var b bytes.Buffer b.WriteString(s) return b.Bytes()}// 拼接转换 []byte 到 stringfunc BytesJoinString(b []byte) string { var s strings.Builder s.Write(b) return s.String()}// 测试拼接转换 string() 性能func Benchmark_BytesJoinString(b *testing.B) { x := []byte("Hello Gopher! Hello Gopher! Hello Gopher!") for i := 0; i < b.N; i++ {  _ = BytesJoinString(x) }}// 测试拼接转换 []byte 性能func Benchmark_StringJoinBytes(b *testing.B) { x := "Hello Gopher! Hello Gopher! Hello Gopher!" for i := 0; i < b.N; i++ {  _ = StringJoinBytes(x) }}运行 go test -bench="." -benchmem ,得到以下结果:goos: darwingoarch: amd64pkg: example/joinBenchmark_BytesJoinString-8             66973782                18.25 ns/op           48 B/op          1 allocs/opBenchmark_StringJoinBytes-8             55316959                21.21 ns/op           64 B/op          1 allocs/opPASSok   example/join 2.112s可以看到,拼接转换每次操作只会分配一次内存,并且耗时在 10 纳秒左右,性能比标准转换还要差。四、总结可以看到,我们在 golang 中可以使用标准转换、强制转换或拼接转换来进行 []byte 和 string 的转换。标准转换是最常用的方式,语法简洁易懂,但可能涉及内存分配和复制操作。强制转换可以避免内存分配和复制操作,性能更高,但需要注意类型安全和数据不变性。拼接转换适用于需要拼接多个字符串或字节切片的场景,可以减少内存分配次数,提高性能。根据具体的使用场景和需求,选择合适的转换方式可以达到最快的速度。
点赞 2
评论 0
全部评论

相关推荐

Lorn的意义:你这种岗位在中国现在要么牛马天天加班,要么关系户进去好吃好喝,8年时间,真的天翻地覆了,对于资本来说你就说一头体力更好的牛马,哎,退伍没有包分配你真的亏了。
点赞 评论 收藏
分享
07-11 11:10
门头沟学院 Java
请问各位大三兄弟们跟hr说多久实习时间到时候可以提前跑路吗?
程序员小白条:问就是六个月以上,可以一年,实习都这样,你入职后想跑就跑
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务