从未处理过多线程程序的PHP开发人员开始学习golang和通道时,可能会发生这种情况。
我正在进行“围棋之旅”的最后一个练习,[Exercise: Web Crawler](在此之前的其他练习中,我没有任何问题)
我正在尝试编写尽可能简单的代码,
我的抓取方法如下所示:
func Crawl(url string, depth int, fetcher Fetcher) {
// kick off crawling by passing initial Url to a Job queue
Queue <- Job{
url,
depth,
}
// make sure we close the Queue channel
defer close(Queue)
// read from the Queue
for job := range Queue {
// if fetched or has hit the bottom of depth,
// just continue right away to pick up next Job
if fetched.Has(job.Url) || job.Depth <= 0 {
continue
}
fres := fetcher.Fetch(job.Url)
fetched.Add(job.Url, fres)
for i := range fres.Urls {
// send new urls just fetched from current url in Job
// to the Queue
Queue <- Job{
fres.Urls[i], job.Depth - 1,
}
}
}
for _, res := range fetched.m {
fmt.Println(res)
}
}
go run
说我不应该编写任何go
代码并回到PHP
:fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.Crawl(0xf37c1, 0x12, 0x4, 0x1600e0, 0x104401c0, 0x104000f0)
/tmp/sandbox452918312/main.go:64 +0x80
main.main()
/tmp/sandbox452918312/main.go:87 +0x60
当然,我已经搜索了这个问题,其结论通常是:“关闭您的聊天室”,我这样做了(是吗?)。
那么,有人可以指出我在这里想念的是什么吗?
完整的代码在这里:https://play.golang.org/p/-98SdVndD6
此练习最惯用的golang方法是什么?我发现了其中的几个。
等等,哪一个似乎是您的干净解决方案?
另外,我是否应将gototines通道仅与一起使用?
最佳答案
您正在“推迟”关闭队列。这意味着“退出此功能(爬网)时关闭队列!”
然后,您将进入一个循环,该循环将一直阻塞,直到发生以下任何一种情况:
在队列开始处添加了一个“作业”(这将允许循环运行一次),然后在第一次运行结束时,循环将阻塞,直到再次满足以上两个条件之一。
注意:通过第一个循环运行可能会向队列中添加更多项目(并因此导致更多迭代),尽管在某些时候,循环的队列将耗尽,并且循环将再次阻塞以等待上述两个条件之一
但是,队列中再也没有添加任何项目(因此#1失败),并且仅在此函数退出后才关闭“队列”,直到退出循环(因此#2失败)之后才发生。
TLDR:您的循环正在等待函数退出,而您的函数正在等待循环退出-死锁
关于go - 了解golang channel 。所有goroutine都在 sleep -死锁[Tour of Go,Crawler],我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43749424/