英文:
Go lang multiplexing all goroutines are asleep - deadlock
问题
我想在这里使用多个Go协程创建一个fan-in函数,返回一个通道。以下是我的代码。
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
var wg, wg2 sync.WaitGroup
func main() {
final := talk(boring("Joe"), boring("Ann"))
for i := 0; i < 10; i++ {
fmt.Println(<-final)
}
fmt.Println("You are both boring I'm leaving")
}
func talk(input1, input2 <-chan string) <-chan string {
out := make(chan string)
go func() {
wg.Add(1)
for {
out <- <-input1
}
}()
go func() {
wg.Add(1)
for {
out <- <-input2
}
}()
wg.Done()
close(out)
return out
}
func boring(msg string) <-chan string {
c := make(chan string)
for i := 0; i < 5; i++ {
c <- fmt.Sprintf("%s%d\n", msg, i)
time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond)
}
return c
}
但是在运行上述代码后,我遇到了一个错误:
所有的goroutine都处于休眠状态 - 死锁
我尝试过关闭通道,但仍然出现错误。我尝试将boring返回的通道分配给Joe和Ann,然后将这些通道传递给talk函数进行多路复用,但仍然没有成功。我是Go语言学习者,对通道的概念还不太清楚。
英文:
I wants to create a fan-in function using multiple go routines returning channel here is my code.
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
var wg, wg2 sync.WaitGroup
func main() {
final := talk(boring("Joe"), boring("Ann"))
for i := 0; i < 10; i++ {
fmt.Println(<-final)
}
fmt.Println("You are both boring I'm leaving")
}
func talk(input1, input2 <-chan string) <-chan string {
out := make(chan string)
go func() {
wg.Add(1)
for {
out <- <-input1
}
}()
go func() {
wg.Add(1)
for {
out <- <-input2
}
}()
wg.Done()
close(out)
return out
}
func boring(msg string) <-chan string {
c := make(chan string)
for i := 0; i < 5; i++ {
c <- fmt.Sprintf("%s%d\n", msg, i)
time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond)
}
return c
}
But I got an error after running above code
> all goroutines are asleep - deadlock
I have tried to close channels but still it is giving me the error. I have tried to assign boring returned channels to Joe and Ann and then pass those channels to talk function for multiplexing still no success. I am new to go learning channels not clear on this concept.
答案1
得分: 2
替代使用等待组(wait groups),你可以使用select
语句:https://tour.golang.org/concurrency/5
select
语句允许一个goroutine等待多个通信操作。
select
语句会阻塞,直到其中一个case可以执行,然后执行该case。如果有多个case都准备好了,它会随机选择一个。
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
final := talk(boring("Joe"), boring("Ann"))
for i := 0; i < 10; i++ {
fmt.Println(<-final)
}
fmt.Println("You are both boring I'm leaving")
}
func talk(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
}
func boring(msg string) <-chan string {
c := make(chan string)
go func() {
for i := 0; i < 5; i++ {
c <- fmt.Sprintf("%s: %d", msg, i)
time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond)
}
}()
return c
}
编辑:
在你给出的示例中,boring
函数没有使用goroutine进行重复的通道发送,这将导致阻塞,因为:
默认情况下,发送和接收操作会阻塞,直到另一侧准备好。这允许goroutine在没有显式锁或条件变量的情况下进行同步。
此外,wg.Done()
需要作为goroutine的一部分。
我通过进行上述更改使其正常工作:https://play.golang.org/p/YN0kfBO6iT
英文:
Instead of wait groups, you can use select
: https://tour.golang.org/concurrency/5
> The select
statement lets a goroutine wait on multiple communication
> operations.
>
> A select
blocks until one of its cases can run, then it executes that
> case. It chooses one at random if multiple are ready.
>
>
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
final := talk(boring("Joe"), boring("Ann"))
for i := 0; i < 10; i++ {
fmt.Println(<-final)
}
fmt.Println("You are both boring I'm leaving")
}
func talk(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
}
func boring(msg string) <-chan string {
c := make(chan string)
go func() {
for i := 0; i < 5; i++ {
c <- fmt.Sprintf("%s: %d", msg, i)
time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond)
}
}()
return c
}
Edit:
In your given example, boring
function doesn't use goroutine for repeated send over channel which will block forever, because:
https://tour.golang.org/concurrency/2
> By default, sends and receives block until the other side is ready.
> This allows goroutines to synchronize without explicit locks or
> condition variables.
Also, wg.Done()
needs to be part of goroutine.
I got it working by doing above changes: https://play.golang.org/p/YN0kfBO6iT
答案2
得分: 1
你不能让一个 goroutine 自己停止,我建议使用类似以下方式向 goroutine 发送信号以退出:
stop := make(chan bool)
go func() {
for {
select {
case <-stop:
return
default:
// 做其他的事情
}
}
}()
// 做其他的事情
// 退出 goroutine
stop <- true
英文:
You cannot stop a goroutine by itself, I suggest signaling the goroutine to quit with something along these lines:
stop := make(chan bool)
go func() {
for {
select {
case <- stop:
return
default:
// Do other stuff
}
}
}()
// Do stuff
// Quit goroutine
stop<- true
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论