Golang 中 string 与 []byte 互转优化

Kevin Bai
3 min readMay 24, 2019

--

在很多项目中都会存在大量的 string 与 []byte 互相转换的情况,在上篇转载于 draveness 的文章 谈 Golang 中的字符串和字节数组 也提到:

无论是从哪种类型转换到另一种都需要对其中的内容进行拷贝,内存拷贝的性能损耗会随着字符串数组和字节长度的增长而增长,所以在做这种类型转换时一定要注意性能上的问题。

从上文的分析来看,如果代码中存在高频的 string 与 []byte 互相转换,尤其字符串长度不定的情况下,势必会影响到整体性能。

但是我们又从那篇文章中可以看到 string 与 []byte 内部结构发现他们及其相似,只区别于 Cap

type StringHeader struct {
Data uintptr
Len int
}
type SliceHeader struct {
Data uintptr
Len int
Cap int
}

接下来我们可以使用一些方法来避免这种大批量的拷贝工作,这个方法就是可以绕过类型检查的 unsafe.Pointer

func str2bytes(s string) []byte {
x := (*[2]uintptr)(unsafe.Pointer(&s))
b := [3]uintptr{x[0], x[1], x[1]}
return *(*[]byte)(unsafe.Pointer(&b))
}

func bytes2str(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}

str2bytes() 首先获得 string 成员的 unsafe.Pointer,并填充到 []byte 结构中,并增加了 Cap 项。而对于 bytes2str() 其实更简单,直接抛弃 Cap 即可。

整个代码地址在 Github 可以查到,下面我们来对比一下这种方式和传统方式的性能对比。

从上图中可以明显的看到性能有大幅度的提升。

参考文章:

  1. Type-Unsafe Pointers

2. 谈 Golang 中的字符串和字节数组

3. Go性能优化技巧

--

--