英文:
all goroutines are asleep deadlock
问题
我正在尝试使用goroutines和channel进行实验。
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
}
如果我运行这个程序,它会给我一个错误,所有的goroutines都处于睡眠状态,发生了死锁。
但是,如果我将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
}
你能帮我理解其中的原因吗?
英文:
I am trying to play around with goroutines and channel
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
}
If i run this program it is giving me error, all goroutines are asleep, deadlock.
But If I put select
inside anonymous goroutine, it works just fine. Working example:
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
}
Can you please help me to understand reasoning behind it.
答案1
得分: 3
for
语句会无限循环,因此<-c
通道永远不会被传递,通道会被填满,但main
线程会因为等待c := fanInNew(a, b)
而被阻塞。
fanInNew()
函数永远不会返回,因为for
循环永远不会结束(而且在select
语句上会阻塞):
func fanInNew(input1, input2 <-chan string) <-chan string {
c := make(chan string)
for { // 无限循环并从输入1和输入2中读取数据
select {
case s := <-input1:
c <- s
case s := <-input2:
c <- s
}
}
return c
}
然后在主线程中,这个函数永远不会返回c
通道:
func main() {
// 永远不会执行到下一行
c := fanInNew(boring("joe"), boring("anh"))
}
因此,你可以将for
循环本身放在goroutine中,就像你在第二个示例中所做的那样。此外,通常goroutine应该返回,要么是因为传递了一条消息(例如通过close()
),要么是因为它们达到了一个返回语句。
无论如何,在第二个示例中,你展示了使用匿名闭包的好方法。传递给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
上进行select
,使用关闭通道,当通道被close()
时可以返回。此外,通常可以使用WaitGroup
来实现这一点。
英文:
The for
statements loops forever, and so the <-c
chan is never passed along and the chans get filled, but the main
thread gets stuck waiting for c := fanInNew(a, b)
.
fanInNew()
never returns because for
loops forever (and blocks on 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
}
Then in the main thread this function never returns the c
chan.
func main() {
// Never gets passed the next line
c := fanInNew(boring("joe"), boring("anh"))
}
So you can put the for
loops themselves in goroutines, as you did in the second example. Also typically goroutines should return, either because you pass a message in (such as by close()
ing), or because they reach a return statement.
In any case, what you have in the 2nd example is great for demonstrating the use of anonymous closures. The chan
passed into the goroutine can be returned elsewhere and enable safe message passing between threads:
c := make(chan string)
go func() {
for {
select {
case s := <-input1:
c <- s
case s := <-input2:
c <- s
}
}
}()
return c
There are a few ways of ending a for loop in an anonymous goroutine, including select on a second chan
, a closing channel, which when close()
ed you can return. Also, typically WaitGroups
can achieve that.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论