Как оценить потребление / распределение памяти канала / мьютекса? - PullRequest
0 голосов
/ 28 января 2020

Я пытаюсь сравнить использование канала для одного значения с использованием мьютекса. Пример канала:

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

График памяти выглядит почти так же, но с разным объемом памяти, но не информативным: enter image description hereenter image description here

Можно ли сравнить потребление памяти каналом и мьютексом?

1 Ответ

2 голосов
/ 28 января 2020

Вы делаете неверный сравнительный анализ. Цитирование из пакета do c из testing:

Пример эталонной функции выглядит следующим образом:

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

Функция эталона должен выполнять целевой код bN раз. Во время выполнения теста производительности bN корректируется до тех пор, пока функция теста не будет работать достаточно долго, чтобы быть надежно синхронизированной.

Также не включайте вызовы 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 байтов.

...