Bytes to String Quickly

Kesa...大约 1 分钟golang

Using unsafe package to convert byte slice to string is more efficient than type conversion.

func BytesToStringUnsafePointer(buf []byte) string {
	return *(*string)(unsafe.Pointer(&buf))
}

After go v1.20

func BytesToStringUnsafePointer2(buf []byte) string {
	return unsafe.String(unsafe.SliceData(buf), len(buf))
}

3. Type Conversion

func BytesToStringTypeConvert(buf []byte) string {
    return string(buf)
}

Benchmark

func BenchmarkBytesToString(b *testing.B) {
    tests := []struct {
       name string
       f    func([]byte) string
    }{
       {name: "UnsafePointer", f: BytesToStringUnsafePointer},
       {name: "UnsafePointerV1.20", f: BytesToStringUnsafePointer2},
       {name: "TypeConvert", f: BytesToStringTypeConvert},
    }

    for k := 10; k <= 100000; k *= 10 {
       buf := genBytes(k)
       for _, t := range tests {
          b.Run(fmt.Sprintf("%-20s_%.e", t.name, float64(k)), func(b *testing.B) {
             for i := 0; i < b.N; i++ {
                t.f(buf)
             }
          })
       }
    }
}

func genBytes(length int) []byte {
    letters := make([]byte, 0, 26)
    var c byte = 'a'
    for ; c <= 'z'; c++ {
       letters = append(letters, c)
    }

    buf := make([]byte, 0, length)
    for i := 0; i < length; i++ {
       idx := rand.Intn(26)
       buf = append(buf, letters[idx])
    }

    return buf
}
image-20230914025639101
image-20230914025639101

If convert []byte to string using unsafe package, it will cause runtime error: unexpected fault address: xxxxx, fatal error: fault

func main() {
    s := "abc"
	buf := StringToBytesUnsafePointer(s)
	printBufInfo(buf)

	buf2 := StringToBytesUnsafePointer2(s)
	printBufInfo(buf2)
    
    // unexpected fault address
    sort.Slice(buf, func(i, j int) bool {
		return buf[i] > buf[j]
	})
	// unexpected fault address
	sort.Slice(buf2, func(i, j int) bool {
		return buf2[i] > buf2[j]
	})
}

func StringToBytesUnsafePointer(s string) []byte {
	return *(*[]byte)(unsafe.Pointer(&s))
}

func StringToBytesUnsafePointer2(s string) []byte {
	return unsafe.Slice(unsafe.StringData(s), len(s))
}

func printBufInfo(buf []byte) {
	format := "%p, %v, len: %d, cap: %d \n"
	fmt.Printf(format, &buf, buf, len(buf), cap(buf))
}

Output:

image-20230914171301088
image-20230914171301088
  • *(*[]byte)(unsafe.Pointer(&s)): will create a capacity unexpected slice

Reference

  1. https://stackoverflow.com/questions/26072921/how-do-i-convert-sizebyte-to-string-in-goopen in new window
  2. https://github.com/golang/go/blob/release-branch.go1.18/src/strings/builder.go#L15open in new window
  3. https://github.com/golang/go/blob/release-branch.go1.20/src/strings/builder.goopen in new window
上次编辑于:
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v2.15.2