Go 字符串各种拼接方案的性能对比(实操最佳方案)
go 语言有多种字符串拼接的方法,比如 +、fmt、strings.Builder、bytes.Buffer 等等….
虽然都可以实现字符串拼接,但是在大量数据字符串拼接的情况下,不同的方法其性能存在一定的差异。
本文作者通过实操、单元测试、基准测试、压力测试对几种拼接方式进行性能测试对比,并得出最终性能最佳最优的拼接方式
字符串拼接在日常开发中非常的常见,go 也有多种方式可以进行字符串拼接,但是当数据量足够大的情况下,不同的拼接方式会产生显著的性能差异。本文通过基准测试数据,带您深入理解Go语言字符串操作的底层机制,文末附结论:最终字符串拼接最优的方式
一、常用拼接方式
- +号拼接
- fmt 占位符
- strings.Builder
- bytes.Buffer
二、性能对比实验
package main
import (
"bytes"
"fmt"
"strings"
"testing"
)
const LOOP = 1000
// BenchmarkStringAdd + 号拼接
func BenchmarkStringAdd(b *testing.B) {
for n := 0; n < b.N; n++ {
var s string
for j := 0; j < LOOP; j++ {
s += "gopher"
}
}
}
// BenchmarkStringBytesBufferAdd bytes.Buffer 拼接
func BenchmarkStringFmtAdd(b *testing.B) {
for i := 0; i < b.N; i++ {
var s string
for j := 0; j < LOOP; j++ {
s = fmt.Sprintf("%sgopher", s)
}
}
}
// BenchmarkStringBuilderAdd strings.Builder 拼接
func BenchmarkStringBuilderAdd(b *testing.B) {
for i := 0; i < b.N; i++ {
var builder strings.Builder
for j := 0; j < LOOP; j++ {
builder.WriteString("gopher")
}
_ = builder.String()
}
}
// BenchmarkStringBytesBufferAdd bytes.Buffer 拼接
func BenchmarkStringBytesBufferAdd(b *testing.B) {
for i := 0; i < b.N; i++ {
var builder bytes.Buffer
for j := 0; j < LOOP; j++ {
builder.WriteString("gopher")
}
_ = builder.String()
}
}
执行测试:
# go test -bench='BenchmarkStringBuilderAdd' -cpu=2 -count=1 -benchmem .
BenchmarkStringBuilderAdd-2 259993 4663 ns/op 24824 B/op 14 allocs/op
PASS
ok learn-go 4.600s
# go test -bench='BenchmarkStringFmtAdd' -cpu=2 -count=1 -benchmem .
BenchmarkStringFmtAdd-2 2973 404782 ns/op 3231129 B/op 2002 allocs/op
PASS
ok learn-go 2.455s
# go test -bench='BenchmarkStringBuilderAdd' -cpu=2 -count=1 -benchmem .
BenchmarkStringBuilderAdd-2 256581 4671 ns/op 24824 B/op 14 allocs/op
PASS
ok learn-go 2.419s
# go test -bench='BenchmarkStringBytesBufferAdd' -cpu=2 -count=1 -benchmem .
BenchmarkStringBytesBufferAdd-2 206992 5818 ns/op 22464 B/op 9 allocs/op
PASS
ok it******.com/learn-go 2.459s
实测结果(MacBook M1 Pro):
从性能对比上可以看得出来,从内存分配、耗时上,strings.Builder、bytes.Buffer 的性能最优
三、各方案特性解析
方案 | 说明 |
---|---|
+ 运算符拼接 | 适用场景:简单临时拼接(<10次) 隐患:每次操作生成新字符串,O(n²)时间复杂度 内存分配:每次操作触发内存重新分配 |
fmt 运算拼接 | 适用场景:需要格式化输出的日志拼接、 混合数据类型(int/float/struct)转换 临时调试输出等非性能敏感场景 |
bytes.Buffer | 高效构建字节,在处理二进制数据时效率较高,注意 buf 过大时会触发 panic |
strings.Builder | 高效构建字符串,使用Grow预分配提升性能 |
结论:
简单拼接场景:+ 运算符拼接、fmt 运算拼接都可以
大量字符串拼接:strings.Builder
适用于处理二进制数据,像文件读写、网络数据传输等场景:bytes.Buffer
版权声明
未经授权,禁止转载本文章。
如需转载请保留原文链接并注明出处。即视为默认获得授权。
未保留原文链接未注明出处或删除链接将视为侵权,必追究法律责任!
本文原文链接: https://fiveyoboy.com/articles/go-concat-string/
备用原文链接: https://blog.fiveyoboy.com/articles/go-concat-string/