字符串拼接在日常开发中是很常见的需求,而且有多种选择,今天我们就来研究研究哪种性能最好。 常见的拼接方式有以下几种:

  • +
  • fmt.Sprintf
  • strings.Join
  • bytes.Buffer
  • strings.Builder

这里直接编写单元测试比较一下性能

源代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package string_join

import (
	"bytes"
	"fmt"
	"strings"
)

var a = "hello"
var b = "world"

var c = []string{a, b}

func StringAdd() string {
	return a + "," + b
}

func StringSprintf() string {
	return fmt.Sprintf("%s,%s", a, b)
}

func StringJoin() string {
	return strings.Join(c, ",")
}

func StringBufferWrite() string {
	var buf bytes.Buffer
	buf.WriteString(a)
	buf.WriteString(",")
	buf.WriteString(b)
	return buf.String()
}

func StringBuilder() string {
	var bul strings.Builder
	bul.WriteString(a)
	bul.WriteString(",")
	bul.WriteString(b)
	return bul.String()
}

编写单元测试

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package string_join

import "testing"

func Benchmark_StringAdd(b *testing.B) {
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		StringAdd()
	}
	b.StopTimer()
}

func Benchmark_StringSprintf(b *testing.B) {
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		StringSprintf()
	}
	b.StopTimer()
}

func Benchmark_StringJoin(b *testing.B) {
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		StringJoin()
	}
	b.StopTimer()
}

func Benchmark_StringBufferWrite(b *testing.B) {
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		StringBufferWrite()
	}
	b.StopTimer()
}

func Benchmark_StringBuilder(b *testing.B) {
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		StringBuilder()
	}
	b.StopTimer()
}

开测: go test -benchmem -run=^$ -bench ^Benchmark_

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ go test -benchmem -run=^$ -bench ^Benchmark_ .
goos: darwin
goarch: arm64
Benchmark_StringAdd-8                   70887246                16.75 ns/op            0 B/op          0 allocs/op
Benchmark_StringSprintf-8               13203135                90.62 ns/op           48 B/op          3 allocs/op
Benchmark_StringJoin-8                  46489255                25.75 ns/op           16 B/op          1 allocs/op
Benchmark_StringBufferWrite-8           26262658                45.11 ns/op           80 B/op          2 allocs/op
Benchmark_StringBuilder-8               32878700                35.91 ns/op           24 B/op          2 allocs/op
PASS
ok      command-line-arguments  7.003s

可以看出来使用+来拼接字符串是性能最优的,然后刨除strings.Join,剩下strings.Builder是最优的选择。 当然上述测试的字符串是很简短的,当字符串变得很长的时候,推荐使用strings.Builder,至于fmt.Sprintf能不用就不要用了。