不生成相同的输出并发 Go 工作线程池

我正在编写一个程序,该程序从文本文件中逐字逐字读取,以使用通道和工作线程池模式计算出现次数

该程序在以程中工作:

  1. 读取文本文件(函数)readText

  2. readText函数将每个单词发送到通道word

  3. 每个戈鲁丁执行对地图中的单词进行计数的函数countWord

  4. 每个戈鲁丁返回一个映射,工作器函数将结构的结果值传递给通道resultC

  5. 测试函数根据来自通道的结果值创建映射resultC

  6. 打印从步骤 5 创建的地图

该程序有效,但当我尝试放置看到过程如下所示fmt.Println(0)

func computeTotal() {

    i := 0

    for e := range resultC {

        total[e.word] += e.count

        i += 1

        fmt.Println(i)

    }

}

程序终止而不显示/计算所有单词


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 all goroutines finished 16 17 18 map[but:1 cat's:1 crouched:1 fur:1 he:2 imperturbable:1 it:1 pointed:1 sat:1 snow:1 stiffly:1 the:1 was:2 with:1] total words: 27 38 ... 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 Time taken for reading the book 5.8145ms

如果我在此处的计算总计函数语句中取消注释 fmt.println(), 程序将正确显示结果,输出如下所示


all goroutines finished

map[a:83 about:4 above:2 absolute:1 accepted:1 across:1 affection:1 after:1 again:5  wonder:2 wood:5 wooded:1 woody:1 work:1 worked:2 world:4 would:11 wrapped:1 wrong:1 yellow:2 yielded:1 yielding:1 counts continues ......]

total words:  856

Time taken for reading the book 5.9924ms

这是我对阅读文本的实现


//ensure close words at the right timing

func readText() {


    file, err := os.Open(FILENAME)

    if err != nil {

        log.Fatal(err)

    }

    defer file.Close()

    scanner := bufio.NewScanner(file)

    scanner.Split(bufio.ScanWords)


    for scanner.Scan() {

        word := strings.ToLower(scanner.Text())

        words <- strings.Trim(word, ".,:;")


    }

    //time.Sleep(1 * time.Second)

    close(words)

}

这是我使用工人池的计数单词实现


//call countWord func,

func workerPool() {

    var wg sync.WaitGroup

    for i := 1; i <= NUMOFWORKER; i++ {

        wg.Add(1)

        go worker(&wg)

    }

    wg.Wait()

    fmt.Println("all goroutines finished")

    close(resultC)

}

我一直在寻找为什么程序没有显示一致的结果,但我还无法弄清楚。如何对程序进行更改,使其产生相同的结果?

素胚勾勒不出你
浏览 112回答 2
2回答

一只甜甜圈

该函数始终返回计数 == 1 的结果。countWord下面是递增计数的函数版本:func countWord(word string, tempMap map[string]int) Result {&nbsp; &nbsp; count := tempMap[word] + 1&nbsp; &nbsp; tempMap[word] = count&nbsp; &nbsp; return Result{word, count}}但要抱住这个想法!该函数假定结果为 1。鉴于问题中的工人总是按预期发送,我们可以通过直接从发送来将工人从图片中剔除。代码如下:computeTotalcountResult{word, 1}computeTotalResult{word, 1}readTextfunc computeTotal() {&nbsp; &nbsp; i := 0&nbsp; &nbsp; for e := range resultC {&nbsp; &nbsp; &nbsp; &nbsp; total[e.word] += e.count&nbsp; &nbsp; &nbsp; &nbsp; i += 1&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(i)&nbsp; &nbsp; }}func readText() {&nbsp; &nbsp; file, err := os.Open(FILENAME)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; log.Fatal(err)&nbsp; &nbsp; }&nbsp; &nbsp; defer file.Close()&nbsp; &nbsp; scanner := bufio.NewScanner(file)&nbsp; &nbsp; scanner.Split(bufio.ScanWords)&nbsp; &nbsp; for scanner.Scan() {&nbsp; &nbsp; &nbsp; &nbsp; word := strings.ToLower(scanner.Text())&nbsp; &nbsp; &nbsp; &nbsp; resultC <- Result{strings.Trim(word, ".,:;"), 1}&nbsp; &nbsp; }&nbsp; &nbsp; close(resultC)}main() {&nbsp; &nbsp; ...&nbsp; &nbsp; go readText()&nbsp; &nbsp; computeTotal()&nbsp; &nbsp; fmt.Println(total)&nbsp; &nbsp; ...}通道操作的开销可能否定了运行和单独戈鲁廷的任何好处。下面是组合成单个戈鲁廷的代码:computeTotalreadTextfunc main() {&nbsp; &nbsp; file, err := os.Open(FILENAME)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; log.Fatal(err)&nbsp; &nbsp; }&nbsp; &nbsp; defer file.Close()&nbsp; &nbsp; scanner := bufio.NewScanner(file)&nbsp; &nbsp; scanner.Split(bufio.ScanWords)&nbsp; &nbsp; var total = map[string]int{}&nbsp; &nbsp; for scanner.Scan() {&nbsp; &nbsp; &nbsp; &nbsp; word := strings.ToLower(strings.Trim(scanner.Text(), ".,:;"))&nbsp; &nbsp; &nbsp; &nbsp; total[word]++&nbsp; &nbsp; }&nbsp; &nbsp; fmt.Println(total)}问题中的函数使我认为您的目标是计算每个工人的单词并合并结果以获得总计。这是代码:countWordfunc computeTotal() {&nbsp; &nbsp; for i := 1; i <= NUMOFWORKER; i++ {&nbsp; &nbsp; &nbsp; &nbsp; m := <-resultC&nbsp; &nbsp; &nbsp; &nbsp; for word, count := range m {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; total[word] += count&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}func workerPool() {&nbsp; &nbsp; for i := 1; i <= NUMOFWORKER; i++ {&nbsp; &nbsp; &nbsp; &nbsp; go worker()&nbsp; &nbsp; }}func worker() {&nbsp; &nbsp; var tempMap = make(map[string]int)&nbsp; &nbsp; for w := range words {&nbsp; &nbsp; &nbsp; &nbsp; tempMap[w]++&nbsp; &nbsp; }&nbsp; &nbsp; resultC <- tempMap}...var resultC = make(chan map[string]int)...func main() {&nbsp; &nbsp; ...&nbsp; &nbsp; go readText()&nbsp; &nbsp; workerPool()&nbsp; &nbsp; computeTotal()&nbsp; &nbsp; ...}

四季花海

您必须通过以下方式重写函数:computeTotalfunc computeTotal(done chan struct{}) {&nbsp; &nbsp; defer close(done)&nbsp; &nbsp; i := 0&nbsp; &nbsp; for e := range resultC {&nbsp; &nbsp; &nbsp; &nbsp; total[e.word] += e.count&nbsp; &nbsp; &nbsp; &nbsp; i += 1&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(i)&nbsp; &nbsp; }}func main() {&nbsp; &nbsp;computeTotalDone := make(chan struct{})&nbsp; &nbsp;go computeTotal(computeTotalDone)&nbsp; &nbsp;...&nbsp; &nbsp;workerPool() //blocking&nbsp; &nbsp;<-computeTotalDone&nbsp; &nbsp;fmt.Println(total)}添加会导致无效结果的原因是您的实现具有争用条件。由于在主函数和函数中打印总结果并行运行,因此不能保证在调用之前处理所有消息。如果没有该功能,您的计算机上的速度就足以产生正确的结果。fmt.Printlnfmt.Println(total)computeTotalcomputeTotalfmt.Println(total)fmt.PrintlncomputeTotal建议的解决方案可确保在调用之前完成。computeTotalfmt.Println(total)
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go