需要帮助以了解为什么select {}不会永远阻止

我正在使用通道实现队列的练习中。具体来说,我正在尝试使用通道的大小来限制并行goroutine的数量。出于智慧,我编写了以下代码:


package main


import "fmt"

import "time"

import "math/rand"


func runTask (t string, ch *chan bool) {

        start := time.Now()

        fmt.Println("starting task", t)

        time.Sleep(time.Millisecond * time.Duration(rand.Int31n(1500))) // fake processing time

        fmt.Println("done running task", t, "in", time.Since(start))

        <- *ch

}


func main() {

        numWorkers := 3

        files := []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j"}


        activeWorkers := make(chan bool, numWorkers)


        for _, f := range files {

                activeWorkers <- true

                fmt.Printf("activeWorkers is %d long.\n", len(activeWorkers))

                go runTask(f, &activeWorkers)

        }

        select{}

}

现在,代码崩溃并带有:


throw: all goroutines are asleep - deadlock!

我的期望是对select的调用将永远阻塞,并使goroutine在没有死锁的情况下终止。


所以我有两个问题:为什么选择不会永远阻塞,并且没有在time.Sleep()中抛出,在for循环之后调用,如何避免死锁?


慕桂英4014372
浏览 227回答 3
3回答

牧羊人nacy

tux21b已经发布了一个更惯用的解决方案,但是我想以另一种方式回答您的问题。select {}会永远阻止,是的。当所有goroutine被阻止时,将发生死锁。如果其他所有goroutine完成,则只剩下被阻塞的主goroutine,这是一个死锁。通常,您希望在所有其他goroutine完成之后在主goroutine中执行某些操作,要么使用它们的结果,要么只是进行清理,为此您将执行tux21b的建议。如果您真的只是想让main完成,而让其余goroutine继续工作,请放在defer runtime.Goexit()main函数的顶部。这将导致它退出而不退出程序。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go