Golang string stitching and builder optimization

Overview

  • + Number stitching
  • fmt stitching
  • Join stitching
  • buffer stitching
  • builder stitching

In the case of less data, these methods are not much different, but when there are many strings to be spliced, it is recommended builder. The + sign connection is suitable for the concatenation of short, constant strings, because the compiler will optimize

+ Number stitching

s := s1+s2+s3

fmt stitching

s := fmt.Sprintf("%v%v",s1,s2)

Join stitching

Receive an array of strings and convert them into a concatenated string

sList := []string{s1,s2}
s := strings.Join(SList,"") 

buffer stitching

Not only can concatenate character strings, but also concatenate bytes, etc.

var b = bytes.Buffer
b.WriteString(s1)
b.WriteString(S2)
s := String() 

builder stitching

var b strings.Builder
b.WriteString(s1)
b.WriteString(s2)
s := b.String()

Optimize the builder

Test code

project\stringBuilder\sb.go

package stringBuilder

import "strings"

func StringBuilder(p []string) string {
	var b strings.Builder
	l:=len(p)
	for i:=0;i<l;i++{
		b.WriteString(p[i])
	}
	return b.String()
}


project\stringBuilder\sb_test.go

package stringBuilder

import "testing"

const TESTSTRING  = "test,"

/*
	初始化函数
	生成一个具有N个字符串的数组
*/

func initStrings(N int) []string{
	s:=make([]string,N)
	for i:=0;i<N;i++{
		s[i]=TESTSTRING
	}
	return s;
}

/*
	测试
	10个字符串
*/
func BenchmarkStringBuilder10(b *testing.B) {
	p:= initStrings(10)
	b.ResetTimer()
	for i:=0;i<b.N;i++{
		StringBuilder(p)
	}
}

/*
	测试
	100个字符串
*/
func BenchmarkStringBuilder100(b *testing.B) {
	p:= initStrings(100)
	b.ResetTimer()
	for i:=0;i<b.N;i++{
		StringBuilder(p)
	}
}
/*
	测试
	1000个字符串
*/
func BenchmarkStringBuilder1000(b *testing.B) {
	p:= initStrings(1000)
	b.ResetTimer()
	for i:=0;i<b.N;i++{
		StringBuilder(p)
	}
}


Test Results

goos: windows
goarch: amd64
pkg: TestProject/stringBuilder
BenchmarkStringBuilder10-4   5163981    228 ns/op      120 B/op       4 allocs/op
BenchmarkStringBuilder100-4  1000000    1150 ns/op     1016 B/op      7 allocs/op
BenchmarkStringBuilder1000-4 107428     11735 ns/op    21240 B/op     13 allocs/op
PASS

builderWhere is slow?

As can be seen from the benchmark results, it is mainly slowed down in multiple memory allocations. If multiple memory allocations cause GC, it will be slower!

builder Source code

// WriteString appends the contents of s to b's buffer.
// It returns the length of s and a nil error.
func (b *Builder) WriteString(s string) (int, error) {
	b.copyCheck()
	b.buf = append(b.buf, s...)
	return len(s), nil
}

To put it simply, it is filled in by appendfunctions []byte b. When the bbyte array is expanded, it will cause memory allocation, which makes the operation slower.

Solution

Reduce the number of memory allocations, which is to b字节数组allocate the size in advancecap

Modify the code

func StringBuilder(p []string,cap int) string {
	var b strings.Builder
	l:=len(p)
	b.Grow(cap)
	for i:=0;i<l;i++{
		b.WriteString(p[i])
	}
	return b.String()
}
//测试代码以10个字符串为例
//修改为如下
func BenchmarkStringBuilder10(b *testing.B) {
	p:= initStrings(10)
	b.ResetTimer()
	cap := 10*len(TESTSTRING)
	for i:=0;i<b.N;i++{
		StringBuilder(p,cap)
	}
}

Test results after optimization

BenchmarkStringBuilder10-4   10027047    114 ns/op    64 B/op    1 allocs/op
BenchmarkStringBuilder100-4  1312066     810 ns/op    512 B/op   1 allocs/op
BenchmarkStringBuilder1000-4  141570     8080 ns/op   5376 B/op   1 allocs/op
PASS

Can be optimized 20%~50%

Guess you like

Origin www.cnblogs.com/Jun10ng/p/12682524.html