目录

Go语言字符串拼接性能对比与最佳实践 - 深度优化指南

字符串拼接在日常开发中非常的常见,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