概観
- +数字ステッチ
- 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%