以下是一个例子:
func main() {
c := make(chan int)
i := 0
go goroutine(c)
c <- i
time.Sleep(10 * time.Second)
}
func goroutine(c chan int) {
for {
num := <- c
fmt.Println(num)
num++
time.Sleep(1 * time.Second)
c <- num
}
}
我在goroutine内部尝试做的是从频道接收号码,打印,增加,并在一秒后将其发送回频道。在此之后我想重复一下这个动作。
但结果是,操作只进行一次。
输出:
0
我做错了吗?
答案 0 :(得分:2)
使用
创建无缓冲的频道c
c := make(chan int)
在无缓冲信道上,操作是对称的,即信道上的每个发送只需要一次接收,每次接收只需要一次发送。您将i
发送到频道,goroutine会将其发送到num
。之后,goroutine将增加的num
发送到频道,但没有人接收它。
简而言之:声明
c <- num
会阻止。
您可以使用1缓冲通道,该通道应该可以使用。
您的代码还有另外一个问题,即您在main
中等待十秒后就解决了这个问题:您不知道您的goroutine何时完成。通常,在这些情况下使用sync.WaitGroup
。 但是:你的goroutine没有完成。在一段时间之后引入你在主goroutine中关闭的chan struct{}
,并且在工作人员goroutine中的两个频道上select
,这是惯用的。
答案 1 :(得分:2)
默认情况下,goroutine通信为synchronous
和unbuffered
:在接收方接受该值之前,发送不会完成。必须有一个接收器准备好从通道接收数据,然后发送者可以直接将其交给接收器。
所以通道发送/接收操作阻塞,直到另一方准备就绪:
1。通道上的发送操作会阻塞,直到接收器可用于同一频道:如果ch
上的值没有收件人,则不能放入其他值这个频道。反过来说:当频道不为空时,ch
不能发送新值!因此,发送操作将等到ch
再次可用。
2. 频道的接收操作会阻塞,直到发送者可用于同一频道:如果频道中没有值,则接收器会阻止。
以下示例说明了这一点:
package main
import "fmt"
func main() {
ch1 := make(chan int)
go pump(ch1) // pump hangs
fmt.Println(<-ch1) // prints only 0
}
func pump(ch chan int) {
for i:= 0; ; i++ {
ch <- i
}
}
因为没有接收器,goroutine会挂起并仅打印第一个数字。
要解决此问题,我们需要定义一个新的goroutine,它在无限循环中从通道读取。
func receive(ch chan int) {
for {
fmt.Println(<- ch)
}
}
然后在main()
:
func main() {
ch := make(chan int)
go pump(ch)
go receive(ch)
}
答案 2 :(得分:1)
您使用无缓冲频道,因此您的goroutine挂在c <- num
上
您应该使用缓冲通道,如下所示:c := make(chan int, 1)