douliao8318 2016-08-08 14:58
浏览 86
已采纳

Goroutines共享一个数组通道:试图解决数据竞争

I try to write a complex program with parallel goroutines. It is my first program with channels ;) Each goroutine returns an array and, unfortunately, the result is "random". If I run 10 times the program, I have 10 different results :(

This is an over simplification of my program, the results is good (maybe because it is too simple) but when I run it with -race argument, there is 4 data races.

I tried to had a close() function but it did not worked.

May you help me to find the mistake ? Thank you very much in advance !

package main

import "fmt"
import "sync"
import "strconv"


func cat_strings(a int, b string) []string{
    var y []string

    j := strconv.Itoa(a)
    y = append(y, j)
    y = append(y, b)
    return y
}

func main() {
    var slice []string
    var wg sync.WaitGroup
    var x []string

    queue := make(chan []string, 10)

    wg.Add(10)
    for i := 0; i < 10; i++ {
        go func(i int) {
            defer wg.Done()
            x = cat_strings(i, "var")
            queue <- x
        }(i)

    }
    //close(queue)

    go func() {
        defer wg.Done()
        for t := range queue {
            slice = append(slice, t...)
        }
    }()

    wg.Wait()
    fmt.Println(slice)
}
  • 写回答

1条回答 默认 最新

  • dreamer1231 2016-08-08 15:11
    关注

    There's two pieces to this fix, don't share the slices between goroutines, and then range over queue synchronously in main.

    import (
        "fmt"
        "strconv"
        "sync"
    )
    
    func cat_strings(a int, b string) []string {
        var y []string
    
        j := strconv.Itoa(a)
        y = append(y, j)
        y = append(y, b)
        return y
    }
    
    func main() {
        var slice []string
        var wg sync.WaitGroup
    
        queue := make(chan []string, 10)
    
        wg.Add(10)
        for i := 0; i < 10; i++ {
            go func(i int) {
                defer wg.Done()
                queue <- cat_strings(i, "var")
            }(i)
    
        }
    
        go func() {
            wg.Wait()
            close(queue)
        }()
    
        for t := range queue {
            slice = append(slice, t...)
        }
    
        fmt.Println(slice)
    }
    

    There's no reason for the extra x slice you're sharing between goroutines. If each goroutine needs another slice, define a new one for each. Sharing a single slice is always going to require extra synchronization.

    The other race is between the goruoutine appending from queue to the slice slice, and the final fmt.Println. There's no reason for those be concurrent since you don't want to print until all values have been read, so finish the for-range loop entirely before printing the final value.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 Oracle触发器记录修改前后的字段值
  • ¥100 为什么这个恒流源电路不能恒流?
  • ¥15 有偿求跨组件数据流路径图
  • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值
  • ¥15 我想咨询一下路面纹理三维点云数据处理的一些问题,上传的坐标文件里是怎么对无序点进行编号的,以及xy坐标在处理的时候是进行整体模型分片处理的吗
  • ¥15 CSAPPattacklab
  • ¥15 一直显示正在等待HID—ISP
  • ¥15 Python turtle 画图
  • ¥15 stm32开发clion时遇到的编译问题
  • ¥15 lna设计 源简并电感型共源放大器