golang 字符串拼接性能比較

背景

最近在做一個服務發現/註冊的agent, 各個服務需要通過這個agent來註冊自己的服務,在完成
開發後,測試性能時發現性能達不到要求,通過pprof 來確認cpu主要耗費在gc上,分析結果主要是由於字符串拼接導致,故需要測試一下字符串拼接的幾種方法的性能;

字符串拼接的幾種方法

  1. 直接使用加號進行拼接
  2. strings.Join()
  3. fmt.Sprintf()
  4. bytes.Buffer

大量字符串拼接性能測試

我們使用的場景主要是大量字符串拼接,所以需要的場景是不斷在字符串上拼接所以測試函數如下:

// fmt.Printf
func BenchmarkFmtSprintfMore(b *testing.B) {
    var s string
    for i := 0; i < b.N; i++ {
        s += fmt.Sprintf("%s%s", "hello", "world")
    }
    fmt.Errorf(s)
}
// 加號 拼接
func BenchmarkAddMore(b *testing.B) {
    var s string
    for i := 0; i < b.N; i++ {
        s += "hello" + "world"
    }
    fmt.Errorf(s)
}

// strings.Join
func BenchmarkStringsJoinMore(b *testing.B) {

    var s string
    for i := 0; i < b.N; i++ {
        s += strings.Join([]string{"hello", "world"}, "")

    }
    fmt.Errorf(s)
}

// bytes.Buffer
func BenchmarkBufferMore(b *testing.B) {

    buffer := bytes.Buffer{}
    for i := 0; i < b.N; i++ {
        buffer.WriteString("hello")
        buffer.WriteString("world")

    }
    fmt.Errorf(buffer.String())
}

執行測試函數

~/gopath/src/test/string  go test -bench="."
goos: darwin
goarch: amd64
pkg: test/string
BenchmarkFmtSprintfMore-4         300000        118493 ns/op
BenchmarkAddMore-4                300000        124940 ns/op
BenchmarkStringsJoinMore-4        300000        117050 ns/op
BenchmarkBufferMore-4           100000000           37.2 ns/op
PASS
ok      test/string 112.294s

從上可以看出使用bytes.buffer的性能是非常高的,如果涉及到大量數據拼接推薦
bytes.buffer{}

單次字符串拼接性能測試


func BenchmarkFmtSprintf(b *testing.B) {
    for i := 0; i < b.N; i++ {
        s := fmt.Sprintf("%s%s", "hello", "world")
        fmt.Errorf(s)
    }

}

func BenchmarkAdd(b *testing.B) {
    for i := 0; i < b.N; i++ {
        s := "hello" + "world"
        fmt.Errorf(s)
    }
}
func BenchmarkStringsJoin(b *testing.B) {
    for i := 0; i < b.N; i++ {
        s := strings.Join([]string{"hello", "world"}, "")
        fmt.Errorf(s)
    }
}
func BenchmarkBuffer(b *testing.B) {

    for i := 0; i < b.N; i++ {
        b := bytes.Buffer{}
        b.WriteString("hello")
        b.WriteString("world")
        fmt.Errorf(b.String())
    }
}

執行測試函數

 ~/gopath/src/test/string  go test -bench="."
goos: darwin
goarch: amd64
pkg: test/string
BenchmarkFmtSprintf-4       10000000           200 ns/op
BenchmarkAdd-4              20000000            93.6 ns/op
BenchmarkStringsJoin-4      10000000           152 ns/op
BenchmarkBuffer-4           10000000           175 ns/op
PASS
ok      test/string 7.818s

從上可以看出單詞調用字符串拼接性能 + > strings.Join > bytes.Buffer > fmt.Sprintf

總結

如果涉及到大量數據拼接推薦 bytes.buffer{}

後記

  1. 當然只是通過bytes.buffer{} 性能還是不夠的,針對這個問題我們通過添加緩存進一步接口qps.
  2. cpu 耗費在gc 上的原因,需要分析golang gc 回收機制, 這是另外一個topic, 之後總結。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章