首页 文章

使用waitgroup和无缓冲通道的竞争条件

提问于
浏览
0

在这篇文章Understanding golang channels: 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 回答

  • 2

    你试图从 histogram 中读取 fmt.Println(histogram) ,它与goroutine的写入不同步,使其变异 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 .

    你可以做的另一件事是等待goroutine变异 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)
    

    或者只是使用 Channels 等待 .

    done := make(chan bool)
    go func() {
        for w := range words {
            histogram[w]++
        }
        done <- true
    }()
    
    wg.Wait()
    close(words)
    <-done
    
    fmt.Println(histogram)
    

相关问题