我正在尝试使用goroutines和频道
package main
import (
"fmt"
"math/rand"
"time"
)
func boring(msg string) <-chan string {
c := make(chan string)
go func() {
for i := 0; ; i++ {
c <- fmt.Sprintf("%s %d", msg, i)
time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond)
}
}()
return c
}
func main() {
c := fanInNew(boring("joe"), boring("anh"))
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
fmt.Println("You both are boring, I am leaving")
}
func fanInNew(input1, input2 <-chan string) <-chan string {
c := make(chan string)
for {
select {
case s := <-input1:
c <- s
case s := <-input2:
c <- s
}
}
return c
}
如果我运行这个程序它会给我错误,所有goroutine都睡着了,死锁。
但如果我将select
放在匿名goroutine中,它就可以了。工作示例:
package main
import (
"fmt"
"math/rand"
"time"
)
func boring(msg string) <-chan string {
c := make(chan string)
go func() {
for i := 0; ; i++ {
c <- fmt.Sprintf("%s %d", msg, i)
time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond)
}
}()
return c
}
func main() {
c := fanInNew(boring("joe"), boring("anh"))
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
fmt.Println("You both are boring, I am leaving")
}
func fanInNew(input1, input2 <-chan string) <-chan string {
c := make(chan string)
go func() {
for {
select {
case s := <-input1:
c <- s
case s := <-input2:
c <- s
}
}
}()
return c
}
请你帮我理解背后的推理。
答案 0 :(得分:2)
for
语句永远循环,因此<-c
chan永远不会传递,chans会被填充,但main
线程会等待c := fanInNew(a, b)
。
fanInNew()
永不返回,因为for
永远循环(以及select
btw上的阻止) :
func fanInNew(input1, input2 <-chan string) <-chan string {
c := make(chan string)
for { // Loop forever and read from inputs 1 and 2
select {
case s := <-input1:
c <- s
case s := <-input2:
c <- s
}
}
return c
}
然后在主线程中,此函数永远不会返回c
chan。
func main() {
// Never gets passed the next line
c := fanInNew(boring("joe"), boring("anh"))
}
所以你可以将for
循环本身放在goroutines中,就像你在第二个例子中所做的那样。 同样通常goroutines应该返回,要么是因为你传递了一条消息(例如通过close()
ing),要么是因为它们到达了一个return语句。
在任何情况下,您在第二个示例中所拥有的内容非常适合演示使用匿名闭包。传入goroutine的chan
可以在其他地方返回,并在线程之间启用安全消息传递:
c := make(chan string)
go func() {
for {
select {
case s := <-input1:
c <- s
case s := <-input2:
c <- s
}
}
}()
return c
有几种方法可以在匿名goroutine中结束for循环,包括选择第二个chan
,结束频道,close()
时你可以返回。此外,通常WaitGroups
可以实现这一目标。