如何基准通道/互斥内存消耗/分配?

How to benchmark channel / mutex memory consumption / allocation?

我尝试比较使用一个值的通道与使用互斥锁。频道示例:

func BenchmarkNewDummy(b *testing.B) {
    one := make(chan string, 1)
    two := make(chan string, 1)
    var wg sync.WaitGroup
    wg.Add(2)
    go doWork(&wg, one)
    go doWork(&wg, two)
    wg.Wait()
    fmt.Println(<-one)
    fmt.Println(<-two)
}

func doWork(wg *sync.WaitGroup, one chan string) {
    defer wg.Done()
    one <- "hell0"
}

命令:

go test -bench=. -benchmem -run BenchmarkNewDummy -cpuprofile cpuCh.out -memprofile memCh.prof 

输出没有提供任何有用的信息

goos: darwin
goarch: amd64
BenchmarkNewDummy-8     hell0
hell0
hell0
hell0
hell0
hell0
hell0
hell0
hell0
hell0
2000000000               0.00 ns/op            0 B/op          0 allocs/op
PASS
ok        0.508s

与互斥情况几乎相同:

func BenchmarkNewDummy(b *testing.B) {
    one := ""
    two := ""
    var wg sync.WaitGroup
    wg.Add(2)
    var mu sync.Mutex
    go func() {
        mu.Lock()
        defer mu.Unlock()
        defer wg.Done()
        one = "hello"
    }()
    go func() {
        mu.Lock()
        defer mu.Unlock()
        defer wg.Done()
        two = "hello"
    }()
    wg.Wait()
    fmt.Println(one)
    fmt.Println(two)
}

输出:

goos: darwin
goarch: 
BenchmarkNewDummy-8     hello
hello
hello
hello
hello
hello
hello
hello
hello
hello
2000000000               0.00 ns/op            0 B/op          0 allocs/op
PASS
ok        0.521s

内存图看起来几乎相同,但互斥体分配了更大的内存,但也没有提供信息:

是否要比较通道和互斥锁的内存消耗?

你做的基准测试是错误的。引用 testing:

的包文档

A sample benchmark function looks like this:

func BenchmarkHello(b *testing.B) {
    for i := 0; i < b.N; i++ {
        fmt.Sprintf("hello")
    }
}

The benchmark function must run the target code b.N times. During benchmark execution, b.N is adjusted until the benchmark function lasts long enough to be timed reliably.

也不要在基准代码中包含 fmt.PrintXX() 调用,否则会扭曲结果。

对这些函数进行基准测试:

func newDummy() {
    one := make(chan string, 1)
    two := make(chan string, 1)
    var wg sync.WaitGroup
    wg.Add(2)
    go doWork(&wg, one)
    go doWork(&wg, two)
    wg.Wait()
    <-one
    <-two
}

func doWork(wg *sync.WaitGroup, one chan string) {
    defer wg.Done()
    one <- "hell0"
}

func newDummy2() {
    one, two := "", ""
    var wg sync.WaitGroup
    wg.Add(2)
    var mu sync.Mutex
    go func() {
        mu.Lock()
        defer mu.Unlock()
        defer wg.Done()
        one = "hello"
    }()
    go func() {
        mu.Lock()
        defer mu.Unlock()
        defer wg.Done()
        two = "hello"
    }()
    wg.Wait()
    _, _ = one, two
}

像这样:

func BenchmarkNewDummy(b *testing.B) {
    for i := 0; i < b.N; i++ {
        newDummy()
    }
}

func BenchmarkNewDummy2(b *testing.B) {
    for i := 0; i < b.N; i++ {
        newDummy2()
    }
}

基准测试:

go test -bench . -benchmem

我得到这样的输出:

BenchmarkNewDummy-4    605662      1976 ns/op     240 B/op      5 allocs/op
BenchmarkNewDummy2-4   927031      1627 ns/op      56 B/op      4 allocs/op

从结果来看,newDummy() 平均执行 5 次分配,共计 250 字节。 newDummy2() 执行 4 次分配,共 56 字节。