当从未处理多线程程序的PHP开发人员开始学习golang和渠道时,可能会发生这种情况。
我参加了Tour of Go的最后一次练习,[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
当然,我已经搜索了这个问题,结论通常是:&#34;关闭你的chans&#34;,我做了(我做过吗?)。
那么,有人可以指出我在这里缺少什么吗?
完整的代码在这里:https://play.golang.org/p/-98SdVndD6
这项运动最常用的golang方式是什么?我找到了一把。
等。哪一个似乎是一个干净的解决方案?
另外,我应该在goroutines中使用仅频道吗?
答案 0 :(得分:1)
您推迟关闭队列。这意味着&#34;当此功能(抓取)退出时关闭队列!&#34;
然后你输入一个阻塞的循环,直到它:
有一个&#39; Job&#39;在开始时添加到队列中(这将允许循环运行一次),然后在第一次运行结束时,循环将阻塞,直到再次满足上述两个条件中的任何一个。
注意:第一个循环的运行可能会向队列添加更多项目(因此导致更多迭代),但在某些时候,循环队列将耗尽并且循环将一次再次阻止等待上述两个条件之一
但是,队列中永远不会再添加任何项目(因此#1失败)和队列&#39;只有在此函数退出后才会关闭,直到循环退出后才会发生(因此#2失败)。
TLDR:你的循环正在等待你的函数退出,你的函数正在等待你的循环退出 - 死锁