头图

简介

使用完整的基准测试代码文件,可以直接运行来比较四种字符串拼接方法的性能。

  • for 索引 += 的方式
  • for range += 的方式
  • strings.Join 的方式
  • strings.Builder 的方式

写一个基准测试文件

echo_bench_test.go

package main

import (
    "os"
    "strings"
    "testing"
)

func echoAll1() string {
    var s, sep string
    for 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 + arg
        sep = " | "
    }
    return s
}

func echoAll3() string {
    return strings.Join(os.Args[:], " , ")
}

// strings.Builder 是 Go 推荐的高效字符串拼接方式,尤其在循环中拼接时,
// 可以减少内存分配。


func echoAll4() string {
    var builder strings.Builder
    for 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.Args
    os.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.Args
    os.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.Args
    os.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.Args
    os.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/op

PASS
ok      example    3.456s

每一行含义:

字段含义
BenchmarkEchoAll1测试函数名
-8使用的 CPU 线程数(8 核)
500000b.N 的值,代表该函数跑了 50 万次
3500 ns/op每次调用耗时 3500 纳秒
120 B/op每次操作分配的字节数(字节越少越好)
5 allocs/op每次操作的内存分配次数(次数越少越好)

Go 的基准测试自动决定运行次数(b.N),直到结果足够稳定。

方法ns/opB/opallocs/op说明
EchoAll13500 ns120 B5+= 每次创建新字符串,开销大
EchoAll22400 ns104 B4range + +=,仍然多次内存分配
EchoAll31600 ns80 B2Join 比较高效
EchoAll4800 ns32 B1strings.Builder 最优

唐青枫
20 声望3 粉丝