Golang文字列のステッチとビルダーの最適化

概観

  • +数字ステッチ
  • fmtのステッチ
  • ステッチに参加
  • バッファステッチ
  • ビルダーステッチ

データが少ない場合、これらの方法はそれほど違いはありませんが、スプライスされる文字列が多い場合に使用することをお勧めしますbuilder+記号接続は、コンパイラが最適化するため、短い定数文字列の連結に適しています。

+数字ステッチ

s := s1+s2+s3

fmtのステッチ

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

ステッチに参加

文字列の配列を受け取り、それらを連結文字列に変換します

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

バッファステッチ

文字列を連結できるだけでなく、バ​​イトなども連結できます。

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

ビルダーステッチ

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

ビルダーを最適化する

テストコード

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)
	}
}


試験結果

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

builderどこが遅いの?

ベンチマーク結果からわかるように、複数のメモリ割り当てでは主に速度が低下します。複数のメモリ割り当てが原因でGCが発生すると、速度が低下します。

builder ソースコード

// 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
}

簡単に言えば、append関数で[]byte b埋められますが、bバイト配列が展開されるとメモリが割り当てられ、処理が遅くなります。

解決策

事前にb字节数组サイズ割り当てるメモリ割り当ての数を減らすcap

コードを変更する

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)
	}
}

最適化後のテスト結果

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

最適化できます20%50%

おすすめ

転載: www.cnblogs.com/Jun10ng/p/12682524.html