Overview
- +號拼接
- fmt拼接
- Join拼接
- buffer拼接
- builder拼接
在少數據的情況下,這幾個方法相差不大,但是當要拼接的字符串很多的時候,推薦使用builder
。而+號連接適用於短小的,常量字符串的拼接,因為編譯器會優化
+號拼接
s := s1+s2+s3
fmt拼接
s := fmt.Sprintf("%v%v",s1,s2)
Join拼接
接收一個字符串數組,轉換為一個拼接好的字符串
sList := []string{s1,s2}
s := strings.Join(SList,"")
buffer拼接
不止可以拼接字符串,還可以拼接byte等
var b = bytes.Buffer
b.WriteString(s1)
b.WriteString(S2)
s := String()
builder拼接
var b strings.Builder
b.WriteString(s1)
b.WriteString(s2)
s := b.String()
對builder進行優化
測試代碼
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%