1. 程式人生 > >Go 字串連線+=與strings.Join效能對比

Go 字串連線+=與strings.Join效能對比

Go字串連線

對於字串的連線大致有兩種方式:
1、通過+號連線

func StrPlus1(a []string) string {
    var s, sep string
    for i := 0; i < len(a); i++ {
        s += sep + a[i]
        sep = " "
    }
    return s
}

2、通過strings.Join連線

func StrPlus2(a []string) string {
    return strings.Join(a, " ")
}

對比兩種方式的效率,通過壓力測試進行對比

import "testing"

func BenchmarkStrPlus1(b *testing.B) {
    for i := 0; i < b.N; i++ {
        StrPlus1([]string{"xxx", "bbb", "aaa"})
    }
}

func BenchmarkStrPlus2(b *testing.B) {
    for i := 0; i < b.N; i++ {
        StrPlus2([]string{"xxx", "bbb", "aaa"})
    }
}

執行壓力測試go test -test.bench=".*"

goos: darwin
goarch: amd64
BenchmarkStrPlus1-4     10000000               127 ns/op
BenchmarkStrPlus2-4     20000000                78.7 ns/op

從本機來看通過+號連線字串每個操作消耗127ns時間,strings.Join消耗78.7ns。效率上strings.Join更高

來看下strings包中Join的實現

// Join concatenates the elements of a to create a single string. The separator string
// sep is placed between elements in the resulting string.
func Join(a []string, sep string) string {
    switch len(a) {
    case 0:
        return ""
    case 1:
        return a[0]
    case 2:
        // Special case for common small values.
        // Remove if golang.org/issue/6714 is fixed
        return a[0] + sep + a[1]
    case 3:
        // Special case for common small values.
        // Remove if golang.org/issue/6714 is fixed
        return a[0] + sep + a[1] + sep + a[2]
    }
    n := len(sep) * (len(a) - 1)
    for i := 0; i < len(a); i++ {
        n += len(a[i])
    }

    b := make([]byte, n)
    bp := copy(b, a[0])
    for _, s := range a[1:] {
        bp += copy(b[bp:], sep)
        bp += copy(b[bp:], s)
    }
    return string(b)
}

可以看出當連線字串數量較大時,是先通過make分配足夠的空間,然後把每個字串copy到空間裡面,而不是每次通過+號來多次分配記憶體。