我是新手,我正在尝试了解 goroutine 中 channel 的工作方式。据我了解,关键字range
可用于迭代 channel 的值,直到 channel 关闭或缓冲区耗尽为止;因此,for range c
将重复循环,直到缓冲区耗尽。
我有以下简单的函数可以为 channel 增加值(value):
func main() {
c := make(chan int)
go printchannel(c)
for i:=0; i<10 ; i++ {
c <- i
}
}
我有两个 printchannel
实现,我不确定为什么行为不同。
实现1:
func printchannel(c chan int) {
for range c {
fmt.Println(<-c)
}
}
输出:1 3 5 7
实现2:
func printchannel(c chan int) {
for i:=range c {
fmt.Println(i)
}
}
输出:0 1 2 3 4 5 6 7 8
我并没有期待这些输出!
想要的输出:0 1 2 3 4 5 6 7 8 9
main
函数和 printchannel
函数是否应该在两个线程上并行运行,一个向 channel 添加值,另一个读取值直到 channel 关闭?我可能在这里遗漏了一些基本的 go/thread 概念,指向它的指针会很有帮助。
非常感谢对此的反馈(以及我对 goroutine 中 channel 操作的理解)!
最佳答案
实现 1. 您从 channel 中读取两次 - range c
和<-c
都在从 channel 中读取内容。
实现2。这是正确的方法。您可能看不到 9 打印的原因是两个 goroutine 可能在并行线程中运行。在这种情况下,它可能会像这样:
- 主协程将 9 发送到 channel 并阻塞直到被读取
- 第二个 goroutine 从 channel 接收到 9
- 主协程解除阻塞并退出。这会终止整个程序,不会给第二个 goroutine 机会打印 9
在这种情况下,你必须同步你的 goroutine。例如,像这样
func printchannel(c chan int, wg *sync.WaitGroup) {
for i:=range c {
fmt.Println(i)
}
wg.Done() //notify that we're done here
}
func main() {
c := make(chan int)
wg := sync.WaitGroup{}
wg.Add(1) //increase by one to wait for one goroutine to finish
//very important to do it here and not in the goroutine
//otherwise you get race condition
go printchannel(c, &wg) //very important to pass wg by reference
//sync.WaitGroup is a structure, passing it
//by value would produce incorrect results
for i:=0; i<10 ; i++ {
c <- i
}
close(c) //close the channel to terminate the range loop
wg.Wait() //wait for the goroutine to finish
}
关于 goroutine 与线程。您不应该混淆它们,并且可能应该理解它们之间的区别。 Goroutines 是绿色线程。关于该主题有无数的博客文章、讲座和 stackoverflow 答案。
关于multithreading - 如何安全地与 Golang 中的 goroutine 中的 channel 交互,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49971237/