几种string转[]byte方法 的比较

看了达达的黑魔法 https://zhuanlan.zhihu.com/p/20010926 ,想尝试下 unsafe 的使用,文中提到了 []byte 转 string 的方法,于是试了下 string to []byte, 对benchmark的结果有些疑问。

如下,写了两个方法:

// DANDER: SHOULD NOT read or write cap of the slice
func quickStringByte(s string) []byte {
    return *(*[]byte)(unsafe.Pointer(&s))
}

// StringByte converts string to byte.
func StringByte(s string) []byte {
    var sh reflect.SliceHeader
    sh.Len = len(s)
    sh.Cap = len(s)
    sh.Data = uintptr(stringPointer(s))
    return *(*[]byte)(unsafe.Pointer(&sh))
}

benchmark代码如下:

func Benchmark_StringByte(b *testing.B) {
    s := "test"
    for i := 0; i < b.N; i++ {
        _ = StringByte(s)
    }
}

func Benchmark_StringByte_Simple(b *testing.B) {
    s := "test"
    for i := 0; i < b.N; i++ {
        _ = []byte(s)
    }
}

func Benchmark_StringByte_Quick(b *testing.B) {
    s := "test"
    for i := 0; i < b.N; i++ {
        _ = quickStringByte(s)
    }
}

结果:

go test -benchmem -bench=StringByte -run=xxx
Benchmark_StringByte-4              1000000000           2.07 ns/op        0 B/op          0 allocs/op
Benchmark_StringByte_Simple-4       200000000            8.03 ns/op        0 B/op          0 allocs/op
Benchmark_StringByte_Quick-4        2000000000           0.68 ns/op        0 B/op          0 allocs/op

疑问是: 为什么每个方法都没有分配内存,但是效率有明显差别?是因为 _ = []byte(s) 把结果舍弃了,导致编译器的优化吗?

已邀请:

silentred

赞同来自:

发现了,还真是

go test -benchmem -bench=StringByte -run=xxx
Benchmark_StringByte-4              500000000            3.43 ns/op        0 B/op          0 allocs/op
Benchmark_StringByte_Simple-4       50000000            31.7 ns/op         8 B/op          1 allocs/op
Benchmark_StringByte_Quick-4        1000000000           2.07 ns/op        0 B/op          0 allocs/op

chuzhaoqian - 我猜一猜

赞同来自:

= []byte(s) 和 = quickStringByte(s) 都是舍弃了结果啊 应该是 _ = []byte(s) 和 ([]byte)(unsafe.Pointer(&s)) 的 比较 ([]byte)(unsafe.Pointer(&s)) 初学者表示没看到过哈

silentred

赞同来自:

根据 StringHeader 结构,尝试了下手动获取 Len 的值,感觉好麻烦

type StringHeader struct {
    Data uintptr
    Len  int
}

s := "testgo"
sHeader := (*reflect.StringHeader)(unsafe.Pointer(&s))
fmt.Printf("ptr is %p %p, %p \n", &s, sHeader, &sHeader.Data)
l := (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(sHeader)) + 8))
fmt.Println("len is", sHeader.Len, *l)

要回复问题请先登录注册