带有 Select 的 Goroutine 不会停止,除非添加打印语句
在 Go Tour 练习 #71 中,使用不带默认值的 select语句可能会导致无限循环,从而阻止 goroutine 退出。使用 nogood 参数运行 71_hang.go 时会遇到此问题,但使用 ok 参数则不会。
两种场景之间的区别在于默认情况下存在额外的 fmt.Print("") 语句select 语句的情况。默认情况下,选择块直到其中一个通道有消息要接收。然而,在默认情况下,即使没有通道有消息可用,select 也会执行默认语句。
在原始代码中,没有 fmt.Print("") 语句,select 语句输入了一个无限循环,因为没有可用消息的通道,并且默认情况下不执行任何操作来允许 goroutine 进行调度。添加 fmt.Print("") 语句允许调度程序调度其他 goroutine 并打破无限循环。
或者,可以修改代码以非阻塞方式使用 select,从而允许其他 goroutine才能正常运行。这可以通过删除默认语句并使用单独的 if 语句来检查抓取计数器是否已达到零来实现,如下面修改后的代码所示:
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 } }
以上是为什么带 Goroutine 的 Go Select 语句会挂起,除非添加 Print 语句?的详细内容。更多信息请关注PHP中文网其他相关文章!