Go通道不会输出传递的数据。

huangapple go评论69阅读模式
英文:

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 (
	&quot;fmt&quot;
	&quot;time&quot;
)

func main() {
	c := make(chan int)
	fmt.Println(&quot;initialized channel&quot;)

	// 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 &lt;- 5
	time.Sleep(time.Second * 3)
	c &lt;- 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&#39;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 (
	&quot;fmt&quot;
)

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 &lt;- 5
	c &lt;- 4
	close(c)
}

huangapple
  • 本文由 发表于 2022年1月14日 13:37:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/70706418.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定