问题:
在 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中文网其他相关文章!