簡介
使用完整的基準測試代碼文件,可以直接運行來比較四種字符串拼接方法的性能。
-
for
索引+=
的方式 -
for range +=
的方式 -
strings.Join
的方式 -
strings.Builder
的方式
寫一個基準測試文件
echo_bench_test.go
package mainimport ("os""strings""testing"
)func echoAll1() string {var s, sep stringfor i := 0; i < len(os.Args); i++ {s += sep + os.Args[i]sep = " "}return s
}func echoAll2() string {s, sep := "", ""for _, arg := range os.Args[:] {s += sep + argsep = " | "}return s
}func echoAll3() string {return strings.Join(os.Args[:], " , ")
}// strings.Builder 是 Go 推薦的高效字符串拼接方式,尤其在循環中拼接時,
// 可以減少內存分配。func echoAll4() string {var builder strings.Builderfor i, arg := range os.Args[:] {if i > 0 {builder.WriteString(" <> ")}builder.WriteString(arg)}return builder.String()
}// ===== Benchmark Functions =====func BenchmarkEchoAll1(b *testing.B) {// 模擬更長參數列表,避免誤差過大originalArgs := os.Argsos.Args = make([]string, 100)for i := range os.Args {os.Args[i] = "arg"}b.ResetTimer()for i := 0; i < b.N; i++ {_ = echoAll1()}os.Args = originalArgs // 恢復
}func BenchmarkEchoAll2(b *testing.B) {originalArgs := os.Argsos.Args = make([]string, 100)for i := range os.Args {os.Args[i] = "arg"}b.ResetTimer()for i := 0; i < b.N; i++ {_ = echoAll2()}os.Args = originalArgs
}func BenchmarkEchoAll3(b *testing.B) {originalArgs := os.Argsos.Args = make([]string, 100)for i := range os.Args {os.Args[i] = "arg"}b.ResetTimer()for i := 0; i < b.N; i++ {_ = echoAll3()}os.Args = originalArgs
}func BenchmarkEchoAll4(b *testing.B) {originalArgs := os.Argsos.Args = make([]string, 100)for i := range os.Args {os.Args[i] = "arg"}b.ResetTimer()for i := 0; i < b.N; i++ {_ = echoAll4()}os.Args = originalArgs
}
運行基準測試
go test -bench=. -benchmem
示例輸出結果(不同機器會略有不同):
goos: darwin
goarch: amd64
pkg: example
BenchmarkEchoAll1-8 500000 3500 ns/op 120 B/op 5 allocs/op
BenchmarkEchoAll2-8 700000 2400 ns/op 104 B/op 4 allocs/op
BenchmarkEchoAll3-8 1000000 1600 ns/op 80 B/op 2 allocs/op
BenchmarkEchoAll4-8 2000000 800 ns/op 32 B/op 1 allocs/opPASS
ok example 3.456s
每一行含義:
字段 | 含義 |
---|---|
BenchmarkEchoAll1 | 測試函數名 |
-8 | 使用的 CPU 線程數(8 核) |
500000 | b.N 的值,代表該函數跑了 50 萬次 |
3500 ns/op | 每次調用耗時 3500 納秒 |
120 B/op | 每次操作分配的字節數(字節越少越好) |
5 allocs/op | 每次操作的內存分配次數(次數越少越好) |
Go
的基準測試自動決定運行次數(b.N
),直到結果足夠穩定。
方法 | ns/op | B/op | allocs/op | 說明 |
---|---|---|---|---|
EchoAll1 | 3500 ns | 120 B | 5 | += 每次創建新字符串,開銷大 |
EchoAll2 | 2400 ns | 104 B | 4 | range + +=,仍然多次內存分配 |
EchoAll3 | 1600 ns | 80 B | 2 | Join 比較高效 |
EchoAll4 | 800 ns | 32 B | 1 | strings.Builder 最優 |