Состояние гонки с группой ожидания и небуферизованным каналом - PullRequest
0 голосов
/ 09 декабря 2018

Получив (правильное) решение моей первоначальной проблемы в этом посте Понимание каналов golang: deadlock , я пришел к несколько иному решению (которое, на мой взгляд, читается лучше:

// Binary histogram counts the occurences of each word.
package main

import (
    "fmt"
    "strings"
    "sync"
)

var data = []string{
    "The yellow fish swims slowly in the water",
    "The brown dog barks loudly after a drink ...",
    "The dark bird bird of prey lands on a small ...",
}

func main() {
    histogram := make(map[string]int)
    words := make(chan string)
    var wg sync.WaitGroup
    for _, line := range data {
        wg.Add(1)
        go func(l string) {
            for _, w := range strings.Split(l, " ") {
                words <- w
            }
            wg.Done()
        }(line)
    }

    go func() {
        for w := range words {
            histogram[w]++
        }
    }()
    wg.Wait()
    close(words)

    fmt.Println(histogram)
}

Это работает, но, к сожалению, он работает против расы, показывает 2 условия гонки:

==================
WARNING: DATA RACE
Read at 0x00c420082180 by main goroutine:
...
Previous write at 0x00c420082180 by goroutine 9:
...
Goroutine 9 (running) created at:
  main.main()

Можете ли вы помочь мне понять, где находится состояние гонки?

1 Ответ

0 голосов
/ 09 декабря 2018

Вы пытаетесь прочитать из histogram в fmt.Println(histogram), который не синхронизирован с записью горутина, мутировавшей с ним histogram[w]++.Вы можете добавить блокировку для синхронизации записи и чтения.

например,

var lock sync.Mutex

go func() {
    lock.Lock()
    defer lock.Unlock()
    for w := range words {
        histogram[w]++
    }
}()

//...
lock.Lock()
fmt.Println(histogram)

Обратите внимание, что вы также можете использовать sync.RWMutex.

Еще одна вещь, которую вы можете сделать, эточтобы дождаться, пока завершится мутация histogram.

var histWG sync.WaitGroup
histWG.Add(1)
go func() {
    for w := range words {
        histogram[w]++
    }
    histWG.Done()
}()

wg.Wait()
close(words)
histWG.Wait()

fmt.Println(histogram)

Или просто использовать канал для ожидания.

done := make(chan bool)
go func() {
    for w := range words {
        histogram[w]++
    }
    done <- true
}()

wg.Wait()
close(words)
<-done

fmt.Println(histogram)
...