为什么在并行处理时可以在 Go 中重用通道?

这是官方教程中的代码片段


package main


import "fmt"


func sum(s []int, c chan int) {

    sum := 0

    for _, v := range s {

        sum += v

    }

    c <- sum // send sum to c

}


func main() {

    s := []int{7, 2, 8, -9, 4, 0}


    c := make(chan int)

    go sum(s[:len(s)/2], c)

    go sum(s[len(s)/2:], c)

    x, y := <-c, <-c // receive from c


    fmt.Println(x, y, x+y)

}

既然我们是并行计算的,每个线程都把结果保存到同一个通道中,这不是把数据搞砸了吗?


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

慕标5832272

通道操作是 goroutine 安全的。你可以在任何 goroutine 中读/写/关闭,而不会破坏任何进出通道的东西。基本上,通道是同步点。无缓冲通道(如您的情况)将在每次写入和读取时阻塞。当您编写代码时,您的代码会阻塞并等待有人开始在另一端阅读。当您阅读您的代码时,您的代码会阻塞并等待有人开始在另一端编写。在您的情况下,goroutines 中的计算将同时完成(不需要并行),但会在通道写入时阻塞。您的主要 goroutine 将在第一次读取时阻塞,读取值。在第二次读取时阻塞,读取值。即使您使用缓冲通道 -&nbsp;c := make(chan int, 2).&nbsp;您的 goroutine 将完成计算,将结果写入通道而不阻塞并终止。什么都不会被破坏。与此同时,主 goroutine 将阻塞通道读取并等待有人写入它。我建议你阅读Effective go&nbsp;,&nbsp;Go Concurrency Patterns并尝试A Tour of Go

长风秋雁

确实,当您从两个不同的 goroutine 通过一个通道发送两个值时,不一定保证排序(除非您已经做了其他事情来协调它们的发送)。但是,在此示例中,排序根本无关紧要。通道上正在发送两个值:前半部分的总和和第二部分的总和。go&nbsp;sum(s[:len(s)/2],&nbsp;c) go&nbsp;sum(s[len(s)/2:],&nbsp;c)由于这两个值唯一用于计算总和,因此顺序根本无关紧要。事实上,如果您运行该示例的次数足够多,您应该会看到它x并且y经常被交换,但总和x+y始终相同。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go