doudeng3008 2018-12-09 14:01
浏览 28
已采纳

等待组和无缓冲通道的竞争状况

After getting (the right) solution to my initial problem in this post Understanding golang channels: deadlock, I have come up with a slightly different solution (which in my opinion reads better:

// 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)
}

It does work, but unfortunately running it against race, it shows 2 race conditions:

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

Can you help me understand where is the race condition?

  • 写回答

1条回答 默认 最新

  • dongxin991209 2018-12-09 14:09
    关注

    You are trying to read from histogram in fmt.Println(histogram) which is not synchronized to the write of the goroutine mutating it histogram[w]++. You can add a lock to synchronize the writes and reads.

    e.g.

    var lock sync.Mutex
    
    go func() {
        lock.Lock()
        defer lock.Unlock()
        for w := range words {
            histogram[w]++
        }
    }()
    
    //...
    lock.Lock()
    fmt.Println(histogram)
    

    Note you can also use a sync.RWMutex.

    Another thing you could do is to wait for the goroutine mutating histogram to finish.

    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)
    

    Or simply use a channel to wait.

    done := make(chan bool)
    go func() {
        for w := range words {
            histogram[w]++
        }
        done <- true
    }()
    
    wg.Wait()
    close(words)
    <-done
    
    fmt.Println(histogram)
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 Mac系统vs code使用phpstudy如何配置debug来调试php
  • ¥15 目前主流的音乐软件,像网易云音乐,QQ音乐他们的前端和后台部分是用的什么技术实现的?求解!
  • ¥60 pb数据库修改与连接
  • ¥15 spss统计中二分类变量和有序变量的相关性分析可以用kendall相关分析吗?
  • ¥15 拟通过pc下指令到安卓系统,如果追求响应速度,尽可能无延迟,是不是用安卓模拟器会优于实体的安卓手机?如果是,可以快多少毫秒?
  • ¥20 神经网络Sequential name=sequential, built=False
  • ¥16 Qphython 用xlrd读取excel报错
  • ¥15 单片机学习顺序问题!!
  • ¥15 ikuai客户端多拨vpn,重启总是有个别重拨不上
  • ¥20 关于#anlogic#sdram#的问题,如何解决?(关键词-performance)