英文:
go channel doesn't output the data it passed
问题
我是你的中文翻译助手,以下是翻译好的内容:
我刚开始学习Go语言,正在尝试使用通道(channels)并发现了这个问题。
问题是,尽管我发送了两个数字,但控制台只打印了一个数字。
输出结果为:
初始化通道
5
英文:
i am new to go, and i was experimenting with channels and found out this.
func main() {
c := make(chan int)
fmt.Println("initialized channel")
go receiver(c)
go helper(c)
for x := range c {
fmt.Println(x)
}
}
func helper(c chan int) {
time.Sleep(time.Second * 3)
c <- 5
time.Sleep(time.Second * 3)
c <- 4
close(c)
}
func receiver(c chan int) {
for x := range c {
fmt.Println(x)
}
}
The issue is even though i am sending two numbers only one number get printed in the console.
initialized channel
5
output
答案1
得分: 2
行为无法预测。有时你的程序会工作,有时不会。我已经解释了代码(带有注释),说明问题出在哪里。
package main
import (
"fmt"
"time"
)
func main() {
c := make(chan int)
fmt.Println("初始化通道")
// 这是一个从 c 接收的接收器(启动的 goroutine)
go receiver(c)
// 这是一个发送器(启动的 goroutine)
go helper(c)
// 这又是一个从 c 接收的接收器
// 注意:由于接收器和 helper 在
// 不同的 goroutine 中启动,控制流最终会到达
// 这里。
// 行为是不可预测的,因为有时候发送到通道的数据
// 可能会在这里接收到,有时候可能会被接收器函数接收到。
for x := range c {
fmt.Println(x)
}
}
func helper(c chan int) {
time.Sleep(time.Second * 3)
c <- 5
time.Sleep(time.Second * 3)
c <- 4
// 当触发这个 close 时,主函数中的接收器
// 可能会退出,因为停止循环的信号是通过信号发送的。
// 紧接着,主函数结束,因此接收器接收到的数据无法
// 被打印出来(有时候也可能会工作),也就是说,
// 在接收器函数的 fmt.Println(x) 之前,主函数就已经退出了。
close(c)
}
func receiver(c chan int) {
for x := range c {
fmt.Println(x)
}
}
要修复它,你可以尝试这样做。还有更多可能的解决方案,但这已经足够好了。我已经删除了 time.Sleep
调用,因为它们对我们来说不相关且为了简洁起见。
package main
import (
"fmt"
)
func main() {
// 初始化通道
c := make(chan int)
// 启动一个 goroutine 发送数据到
// 通道。同时,只有发送方知道何时停止发送,
// 所以只有发送方关闭通道。对一个已关闭的
// 通道进行发送操作会引发 panic。
go send(c)
// 由于 send 在异步运行,控制流会到达这里,即接收器。
// 它会循环接收通道 c 中的数据,直到 c 被关闭,并且保证接收到
// 发送到通道 c 的每个数据,然后退出。
for x := range c {
fmt.Println(x)
}
}
// 向 c 发送数据
func send(c chan int) {
c <- 5
c <- 4
close(c)
}
英文:
Behavior cannot be predicted. Sometimes your program would work, sometimes it won't. I have explained the code (with comments) where the problem is happening.
package main
import (
"fmt"
"time"
)
func main() {
c := make(chan int)
fmt.Println("initialized channel")
// This is a receiver receiving from c (spawned goroutine)
go receiver(c)
// This is a sender (spawned goroutine)
go helper(c)
// This is again a receiver receiving from c
// NOTE: As reciever and helper are spawned in
// separate goroutine, control eventually reaches
// here.
// Behaviour is unpredictable as sometimes the data
// sent to the channel might be recieved here and
// sometimes it might be recieved by the receiver function.
for x := range c {
fmt.Println(x)
}
}
func helper(c chan int) {
time.Sleep(time.Second * 3)
c <- 5
time.Sleep(time.Second * 3)
c <- 4
// When this close is triggered, the receiver in main
// could get exited as the signal to stop ranging is sent
// using signal. Right after that the main function ends
// such that data recieved by the receiver couldn't get
// printed (sometimes it would work as well) i.e., main
// exited right before fmt.Println(x) in receiver function.
close(c)
}
func receiver(c chan int) {
for x := range c {
fmt.Println(x)
}
}
To fix it, you can try this. There are more possible solutions, but this is good enough. I have removed time.Sleep
calls as they are not relevant to us and for brevity.
package main
import (
"fmt"
)
func main() {
// Initialize the channel
c := make(chan int)
// Spawn a goroutine that sends data to the
// channel. Also, it is expected from the sender
// only to close the channel as it only knows
// when then send stops. Send to a closed
// channel would panic.
go send(c)
// As send is running asynchronously, control
// reaches here i.e., the receiver. It ranges until
// c is closed and is guaranteed to receive every
// date sent to channel c and then exit.
for x := range c {
fmt.Println(x)
}
}
// send data to c
func send(c chan int) {
c <- 5
c <- 4
close(c)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论