为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
慕桂英4014372 2021-05-02 10:11:02
我正在使用通道实现队列的练习中。具体来说,我正在尝试使用通道的大小来限制并行goroutine的数量。出于智慧,我编写了以下代码:package mainimport "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循环之后调用,如何避免死锁?
查看完整描述

3 回答

?
牧羊人nacy

TA贡献1862条经验 获得超7个赞

tux21b已经发布了一个更惯用的解决方案,但是我想以另一种方式回答您的问题。select {}会永远阻止,是的。当所有goroutine被阻止时,将发生死锁。如果其他所有goroutine完成,则只剩下被阻塞的主goroutine,这是一个死锁。

通常,您希望在所有其他goroutine完成之后在主goroutine中执行某些操作,要么使用它们的结果,要么只是进行清理,为此您将执行tux21b的建议。如果您真的只是想让main完成,而让其余goroutine继续工作,请放在defer runtime.Goexit()main函数的顶部。这将导致它退出而不退出程序。


查看完整回答
反对 回复 2021-05-10
  • 3 回答
  • 0 关注
  • 226 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信