我正在实现一个网络爬虫,我有一个Parse
函数,它将一个链接作为输入,并应该返回页面中包含的所有链接。
我想尽可能快地使用例行程序。为此,我想创建一个工人池。
我设置了一个表示链接links := make(chan string)
的字符串通道,并将其作为参数传递给Parse
函数。我希望工人通过一个独特的渠道进行沟通。当函数启动时,它会从links
获取一个链接,为页面中找到的每个有效链接解析它和**,将链接添加到links
。
func Parse(links chan string) {
l := <- links
// If link already parsed, return
for url := newUrlFounds {
links <- url
}
}
但是,此处的主要问题是指示何时找不到更多链接。我想到的一种方法是在所有工人完成之前等待。但我不知道如何在Go中这样做。
答案 0 :(得分:1)
正如蒂姆已经评论过的那样,不要使用相同的渠道来阅读和写作工人。这将最终陷入僵局(即使缓冲,因为墨菲)。
更简单的设计就是每个URL只启动一个goroutine。缓冲通道可以作为一个简单的信号量来限制并发解析器的数量(由于它们被阻塞而无法执行任何操作的goroutine通常可以忽略不计)。使用sync.WaitGroup等待所有工作完成。
package main
import (
"sync"
)
func main() {
sem := make(chan struct{}, 10) // allow ten concurrent parsers
wg := &sync.WaitGroup{}
wg.Add(1)
Parse("http://example.com", sem, wg)
wg.Wait()
// all done
}
func Parse(u string, sem chan struct{}, wg *sync.WaitGroup) {
defer wg.Done()
sem <- struct{}{} // grab
defer func() { <-sem }() // release
// If URL already parsed, return.
var newURLs []string
// ...
for u := range newURLs {
wg.Add(1)
go Parse(u)
}
}