Go 中一些操作的性能对比

这篇博客对比一些操作的性能情况。

  • 循环遍历 slice 各元素
  • 字符串拼接

循环遍历 slice 各元素

以 RoundRobin 的实例进行说明。在 RoundRobin 中有两种方法返回可用的服务地址

1
2
3
4
type roundrobin struct {
i int // 服务地址索引
servers []string // 可用的服务地址
}

第一种,每次索引加一后取余数:

1
2
3
4
5
6
func (r *roundrobin) module() string {
s := r.servers[r.i]
r.i++
r.i %= len(r.servers)
return s
}

第二种,每次索引加一后,判断如果加到最大将索引再置为 0:

1
2
3
4
5
6
7
8
func (r *roundrobin) check() string {
s := r.servers[r.i]
r.i++
if r.i == len(r.servers) {
r.i = 0
}
return s
}

这两种方法结果相同,但性能有一个数量级的差距(查看完整代码):

1
2
BenchmarkModule-4   	100000000	        13.9 ns/op
BenchmarkCheck-4 2000000000 1.49 ns/op

字符串拼接

测试四种拼接方法,两种字符长度(5个字节和500个字节),两种字符个数(4个字符串和100个字符串)。一共 4×2×2=16个结果。

四种拼接方法如下(查看完整代码

fmt.Sprintf():

1
2
3
func byFmt(s []string) string {
return fmt.Sprintf("%s%s%s%s", s[0], s[1], s[2], s[3])
}

使用加号一次拼接

1
2
3
func byPlusOnce(s []string) string {
return s[0] + s[1] + s[2] + s[3]
}

使用加号多次拼接:

1
2
3
4
5
6
7
8
func byPlusSplit(s []string) string {
ret := ""
ret += s[0]
ret += s[1]
ret += s[2]
ret += s[3]
return ret
}

使用 buffer

1
2
3
4
5
6
7
8
func byBuffer(s []string) string {
buf := bytes.Buffer{}
buf.WriteString(s[0])
buf.WriteString(s[1])
buf.WriteString(s[2])
buf.WriteString(s[3])
return buf.String()
}

测试结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ go test -bench BenchmarkConcat*
BenchmarkConcatShortString/fmt-4 2000000 507 ns/op
BenchmarkConcatShortString/plusOnce-4 20000000 74.6 ns/op
BenchmarkConcatShortString/plusSplit-4 10000000 182 ns/op
BenchmarkConcatShortString/buffer-4 10000000 164 ns/op

BenchmarkConcatLongString/fmt-4 2000000 912 ns/op
BenchmarkConcatLongString/plusOnce-4 3000000 448 ns/op
BenchmarkConcatLongString/plusSplit-4 1000000 1058 ns/op
BenchmarkConcatLongString/buffer-4 1000000 2046 ns/op

BenchmarkConcatManyShortString/fmt-4 200000 8125 ns/op
BenchmarkConcatManyShortString/plusOnce-4 2000000 947 ns/op
BenchmarkConcatManyShortString/plusSplit-4 200000 11207 ns/op
BenchmarkConcatManyShortString/buffer-4 1000000 2214 ns/op

BenchmarkConcatManyLongString/fmt-4 100000 15411 ns/op
BenchmarkConcatManyLongString/plusOnce-4 200000 7006 ns/op
BenchmarkConcatManyLongString/plusSplit-4 3000 438927 ns/op
BenchmarkConcatManyLongString/buffer-4 50000 31283 ns/op

根据测试结果速度最快的是byPlusOnce(),而不是网上说的byBuffer()