如何根据goroutine返回的值停止goroutine

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)

这可能吗?哪里错了

icz*_*cza 5

问题是在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)