2 回答
TA贡献1828条经验 获得超6个赞
default在选择select更改的方式中添加一条语句。如果没有默认语句,则select将阻止等待通道上的任何消息。使用默认语句时,select将在每次从通道中读取无内容时运行默认语句。在您的代码中,我认为这会造成无限循环。把fmt.Print在声明中允许调度安排其它够程。
如果您像这样更改代码,则它可以正常工作,并以非阻塞方式使用select,这将允许其他goroutines正常运行。
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
}
}
如果使用GOMAXPROCS = 2,则可以使原始代码正常工作,这是调度程序在无限循环中忙碌的另一个提示。
请注意,goroutine是合作安排的。我对您的问题不完全了解,这select是goroutine应该产生的点-我希望其他人可以解释为什么您的示例中没有它。
TA贡献1993条经验 获得超5个赞
您拥有100%的CPU负载,因为几乎所有情况下都会执行默认情况,这会导致无限循环,因为它会一遍又一遍地执行。在这种情况下,Go调度程序在设计上不会将控制权交给另一个goroutine。因此,任何其他goroutine将永远没有机会进行设置,crawling != 0
而您将遇到无限循环。
我认为,如果要使用select语句,则应删除默认情况,而应创建另一个通道。
否则,运行时程序包将帮助您走脏路:
runtime.GOMAXPROCS(2)
将起作用(或导出GOMAXPROCS = 2),这样您将拥有多个OS线程执行runtime.Gosched()
不时致电内部抓取。即使CPU负载为100%,这也将明确地将控制权传递给另一个Goroutine。
编辑:是的,以及fmt.Printf之所以有所作为的原因:因为它明确地将控制权传递给某些syscall东西...;)
- 2 回答
- 0 关注
- 222 浏览
添加回答
举报