首页 >后端开发 >Golang >为什么 Go `select` 语句在没有 `default` 情况下挂起以及如何修复?

为什么 Go `select` 语句在没有 `default` 情况下挂起以及如何修复?

Barbara Streisand
Barbara Streisand原创
2024-11-24 06:31:15382浏览

Why Does a Go `select` Statement Hang Without a `default` Case and How Can It Be Fixed?

带有 Select 的 Goroutine 在没有 fmt.Print() 的情况下不会停止

问题:

在 Go Tour 练习中#71、使用 go run 71_hang.go nogood 会导致程序无限期运行,而 go运行 71_hang.go 正常,按预期工作。唯一的区别是在 select 语句的 default case 中添加了 fmt.Print("")。

说明:

select 中的 default 语句发生变化声明的行为。如果没有默认值,请选择块,直到通道上有消息为止。使用默认值时,每次从通道中没有任何内容可读取时,select 都会执行默认语句。

在原始代码中,默认语句会创建一个无限循环。由于调度器无法调度其他goroutine,导致程序无限期运行。

解决方案1:

去掉default语句,使用非阻塞select:

for {
    select {
        case todo := <-toDoList:
            if todo.depth > 0 && !visited[todo.url] {
                crawling++
                visited[todo.url] = true
                go crawl(todo, fetcher, toDoList, doneCrawling)
            }
        case <-doneCrawling:
            crawling--
    }
    if crawling == 0 {
        break
    }
}

解决方案2:

保留默认语句,但确保 goroutine 产生。实现此目的的一种方法是使用 GOMAXPROCS=2,它允许调度程序使用多个内核。

附加说明:

Goroutines 是协作调度的。 Select 是 goroutine 应该屈服的点。然而,在给定的示例中,没有 fmt.Print() 语句时 select 不会产生结果的原因尚未完全理解,需要进一步调查。

以上是为什么 Go `select` 语句在没有 `default` 情况下挂起以及如何修复?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn