lns*_*shi 4 channel go goroutine
就像在这里我创建了一个游乐场样本:sGgxEh40ev,但无法让它工作.
quit := make(chan bool)
res := make(chan int)
go func() {
idx := 0
for {
select {
case <-quit:
fmt.Println("Detected quit signal!")
return
default:
fmt.Println("goroutine is doing stuff..")
res <- idx
idx++
}
}
}()
for r := range res {
if r == 6 {
quit <- true
}
fmt.Println("I received: ", r)
}
Run Code Online (Sandbox Code Playgroud)
输出:
goroutine is doing stuff..
goroutine is doing stuff..
I received: 0
I received: 1
goroutine is doing stuff..
goroutine is doing stuff..
I received: 2
I received: 3
goroutine is doing stuff..
goroutine is doing stuff..
I received: 4
I received: 5
goroutine is doing stuff..
goroutine is doing stuff..
fatal error: all goroutines are asleep - deadlock!
Run Code Online (Sandbox Code Playgroud)
这可能吗?哪里错了
问题是在goroutine中你使用a select来检查它是否应该中止,但你使用default分支来做其他工作.
的default,如果没有通信(中列出分支被执行case分支)可以继续进行.因此,在每次迭代中quit都会检查通道,但如果无法从中接收(无需退出),default则执行分支,无条件地尝试发送值res.现在如果主goroutine还没有准备好接收它,那将是一个僵局.这正是发送值时发生的情况6,因为那时主goroutine尝试发送一个值quit,但是如果worker goroutine在default分支中试图发送res,那么两个goroutine都尝试发送一个值,没有一个是试着收到!两个通道都是无缓冲的,因此这是一个死锁.
在worker goroutine中,您必须res使用适当的case分支发送值,而不是在default分支中:
select {
case <-quit:
fmt.Println("Detected quit signal!")
return
case res <- idx:
fmt.Println("goroutine is doing stuff..")
idx++
}
Run Code Online (Sandbox Code Playgroud)
在主要的goroutine中你必须从for循环中断开,这样主要的goroutine才能结束,所以程序也可以结束:
if r == 6 {
quit <- true
break
}
Run Code Online (Sandbox Code Playgroud)
这次输出(在Go Playground上试试):
goroutine is doing stuff..
I received: 0
I received: 1
goroutine is doing stuff..
goroutine is doing stuff..
I received: 2
I received: 3
goroutine is doing stuff..
goroutine is doing stuff..
I received: 4
I received: 5
goroutine is doing stuff..
goroutine is doing stuff..
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1609 次 |
| 最近记录: |