GoLang中拼接字符串性能优化方法详解
raoxiaoya 人气:0字符串在内存中是不可变的,放在只读内存段,因此你可以使用str[0]
来访问,但是不能使用str[0]='a'
来修改。
修改字符串实际上是重新放入新的地址,因此拼接字符串可能出现的性能问题就是频繁的内存分配,比如:
func s1(ids []string) (s string) { for _, id := range ids { s += id } return }
在golang中,具有预先分配内存特性的是切片,如果预先就分配好内存,然后再依次将字符串装进去就避免了内存的频繁分配。
再来看看strings
包的实现
func Join(elems []string, sep string) string { switch len(elems) { case 0: return "" case 1: return elems[0] } n := len(sep) * (len(elems) - 1) for i := 0; i < len(elems); i++ { n += len(elems[i]) } var b Builder b.Grow(n) b.WriteString(elems[0]) for _, s := range elems[1:] { b.WriteString(sep) b.WriteString(s) } return b.String() }
主要就用到strings.Builder
对象,它包含一个切片。
type Builder struct { addr *Builder // of receiver, to detect copies by value buf []byte }
Builder
的Grow
方法就是主动扩容切片的容积。
// grow copies the buffer to a new, larger buffer so that there are at least n // bytes of capacity beyond len(b.buf). func (b *Builder) grow(n int) { buf := make([]byte, len(b.buf), 2*cap(b.buf)+n) copy(buf, b.buf) b.buf = buf } // Grow grows b's capacity, if necessary, to guarantee space for // another n bytes. After Grow(n), at least n bytes can be written to b // without another allocation. If n is negative, Grow panics. func (b *Builder) Grow(n int) { b.copyCheck() if n < 0 { panic("strings.Builder.Grow: negative count") } if cap(b.buf)-len(b.buf) < n { b.grow(n) } }
加载全部内容