所有频道都陷入僵局

时间:2018-04-11 04:42:25

标签: go channel

我正在尝试使用for循环,它不断地将字符串发送到不同goroutine读取的不同通道。然而,它给了我错误“所有goroutines都睡着了 - 死锁!”为什么会这样?我搜索了一些答案,但我找不到这种情况的答案。

func main() {
    var chans []chan string

    for i := 0; i < 3; i++ {
        chans = append(chans, make(chan string))
    }

    for i := 0; i < 3; i++ {
        go sendString(chans[i])
    }

    for str := range chans[0] {
        fmt.Print(str)
    }
}

func sendString(ch chan string) {
    ch <- "a"
    ch <- "b"
    ch <- "c"
    ch <- "d"
}

错误在这里。它打印“abcd”,然后生成错误,如果我删除了打印循环,程序不会生成错误。

abcdfatal error: all goroutines are asleep - deadlock!

 goroutine 1 [chan receive]:
main.main()
    C:/Users/YuanZheng Hu/Desktop/Go Test/test/test.go:18 +0x28d

goroutine 19 [chan send]:
main.sendString(0xc04203c120)
    C:/Users/YuanZheng Hu/Desktop/Go Test/test/test.go:24 +0x42
created by main.main
    C:/Users/YuanZheng Hu/Desktop/Go Test/test/test.go:15 +0x175

goroutine 20 [chan send]:
main.sendString(0xc04203c180)
    C:/Users/YuanZheng Hu/Desktop/Go Test/test/test.go:24 +0x42
created by main.main
    C:/Users/YuanZheng Hu/Desktop/Go Test/test/test.go:15 +0x175
exit status 2

我使用WaitGroup做了版本,但似乎不正确,并给了我同样的错误“所有goroutines都睡着了 - 死锁!”我在下面的代码中哪里做错了?

func main() {
var myWaitGroup sync.WaitGroup
ch := make(chan string)
myWaitGroup.Add(1)
go sendString(ch, &myWaitGroup)


myWaitGroup.Wait()
close(ch)

time.Sleep(1 * time.Second)
}
func sendString(ch chan string, pg *sync.WaitGroup) {
ch <- "a"
ch <- "b"
ch <- "c"
ch <- "d"
defer pg.Done()

}

1 个答案:

答案 0 :(得分:7)

第二个for循环将阻塞,直到通道关闭,因此您需要在发送功能中将其关闭。此外,您只从第一个通道读取,因此一些数据丢失。这样做:

func main() {
    var chans []chan string

    for i := 0; i < 3; i++ {
        chans = append(chans, make(chan string))
    }

    for i := 0; i < 3; i++ {
        go sendString(chans[i])
    }

    for i := 0; i < 3; i++ {
        for str := range chans[i] {
            fmt.Print(str)
        }
    }

}
func sendString(ch chan string) {
    ch <- "a"
    ch <- "b"
    ch <- "c"
    ch <- "d"
    close(ch)
}

将产生:

abcdabcdabcd

https://play.golang.org/p/7SoDKChnTbz

如果您希望根据评论使用单个频道执行此操作,那么您可以添加一个等待组,以便在所有go例程完成后关闭频道:

func main() {
    c := make(chan string)
    var wg sync.WaitGroup

    for i := 0; i < 3; i++ {
        wg.Add(1)
        go func() {
            sendString(c)
            wg.Done()
        }()
    }

    go func() {
        wg.Wait()
        close(c)
    }()

    for str := range c {
        fmt.Print(str)
    }

}
func sendString(ch chan string) {
    ch <- "a"
    ch <- "b"
    ch <- "c"
    ch <- "d"
}

https://play.golang.org/p/E_awt8UBK9v