性能测试之字符串拼接

Golang 字符串拼接性能对比

  • 测试平台: M1 Macbook Pro
  • golang版本: 1.18.3

测试代码

package string_join

import (
	"fmt"
	"strings"
	"testing"
)

const TestText = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

var (
	TenTestTextList      []string
	ThousandTestTextList []string
)

func init() {
	for i := 0; i < 10; i++ {
		TenTestTextList = append(TenTestTextList, TestText)
	}
	for i := 0; i < 1000; i++ {
		ThousandTestTextList = append(ThousandTestTextList, TestText)
	}
}

func BenchmarkForPlusBy10TestText(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var res string
		for i := 0; i < 10; i++ {
			res += TestText
		}
		_ = res
	}
}

func BenchmarkForFmtBy10TestText(b *testing.B) {
	for i := 0; i < b.N; i++ {
		res := fmt.Sprintf("%s%s%s%s%s%s%s%s%s%s", TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText)
		_ = res
	}
}

func BenchmarkForStringsJoinBy10TestText(b *testing.B) {
	for i := 0; i < b.N; i++ {
		res := strings.Join(TenTestTextList, "")
		_ = res
	}
}

func BenchmarkForStringsBuildBy10TestText(b *testing.B) {
	for i := 0; i < b.N; i++ {
		n := 0
		for j := range TenTestTextList {
			n += len(TenTestTextList[j])
		}
		var res strings.Builder
		res.Grow(n)
		for j := range TenTestTextList {
			res.WriteString(TenTestTextList[j])
		}
		_ = res.String()
	}
}

func BenchmarkForPlusBy1000TestText(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var res string
		for i := 0; i < 1000; i++ {
			res += TestText
		}
		_ = res
	}
}

func BenchmarkForFmtBy1000TestText(b *testing.B) {
	for i := 0; i < b.N; i++ {
		res := fmt.Sprintf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText, TestText)
		_ = res
	}
}

func BenchmarkForStringsJoinBy1000TestText(b *testing.B) {
	for i := 0; i < b.N; i++ {
		res := strings.Join(ThousandTestTextList, "")
		_ = res
	}
}

func BenchmarkForStringsBuildBy1000TestText(b *testing.B) {
	for i := 0; i < b.N; i++ {
		n := 0
		for j := range ThousandTestTextList {
			n += len(ThousandTestTextList[j])
		}
		var res strings.Builder
		res.Grow(n)
		for j := range ThousandTestTextList {
			res.WriteString(ThousandTestTextList[j])
		}
		_ = res.String()
	}
}

测试结果

go test -bench=. -benchmem -run=none

goos: darwin
goarch: arm64
pkg: golang_benchmark/string_join
BenchmarkForPlusBy10TestText-8                   2650404             428.9 ns/op            3456 B/op          9 allocs/op
BenchmarkForFmtBy10TestText-8                    6026557             197.9 ns/op             640 B/op          1 allocs/op
BenchmarkForStringsJoinBy10TestText-8            9651046             127.0 ns/op             640 B/op          1 allocs/op
BenchmarkForStringsBuildBy10TestText-8          12190377             95.73 ns/op             640 B/op          1 allocs/op
BenchmarkForPlusBy1000TestText-8                     648           1860594 ns/op        33565074 B/op       1001 allocs/op
BenchmarkForFmtBy1000TestText-8                    36580             33729 ns/op          351215 B/op         21 allocs/op
BenchmarkForStringsJoinBy1000TestText-8           118501             10976 ns/op           65536 B/op          1 allocs/op
BenchmarkForStringsBuildBy1000TestText-8          150084              6956 ns/op           65536 B/op          1 allocs/op
PASS
ok      golang_benchmark/string_join    11.529s

测试结论

  • 尽量不要使用”+”进行字符串拼接(尤其是在长文本拼接的时候,因为会有大量的值copy)
  • 用strings.Builder的性能最好(前提是要预先Grow好长度)
  • strings.Join的底层逻辑和strings.Builder相同,只是多了对sep的处理
更新于