等待所有goroutine完成并合并结果
我很难理解Goroutine、频道和所有同步的东西。我相信我理解这些概念,但我遗漏了几行连接我所有信息的线路。而且,大多数的例子感觉太简单了,所以我不能正确地理解实际发生的事情 我正在为网站编写一个简单的分析工具。其中一个功能是检查是否可以访问此网站上的所有链接。显然,每个网站上都有很多链接,所以它似乎是一个很好的goroutines候选网站。问题是,在安排所有goroutine之后,我需要返回所有结果,以便将它们一次全部呈现给用户 到目前为止,我得到的是:等待所有goroutine完成并合并结果,go,channel,goroutine,goquery,Go,Channel,Goroutine,Goquery,我很难理解Goroutine、频道和所有同步的东西。我相信我理解这些概念,但我遗漏了几行连接我所有信息的线路。而且,大多数的例子感觉太简单了,所以我不能正确地理解实际发生的事情 我正在为网站编写一个简单的分析工具。其中一个功能是检查是否可以访问此网站上的所有链接。显然,每个网站上都有很多链接,所以它似乎是一个很好的goroutines候选网站。问题是,在安排所有goroutine之后,我需要返回所有结果,以便将它们一次全部呈现给用户 到目前为止,我得到的是: func links(u *url.
func links(u *url.URL, d *goquery.Document) (links []models.Link) {
wg := sync.WaitGroup{}
d.Find("a[href]").Each(func(index int, item *goquery.Selection) {
go func() {
wg.Add(1)
href, _ := item.Attr("href")
url, _ := url.Parse(href)
var internal bool
if url.Host == "" {
url.Scheme = u.Scheme
url.Host = u.Host
}
links = append(links, models.Link{
URL: url,
Reachable: Reachable(url.String()),
})
wg.Done()
}()
})
wg.Wait()
return
}
func Reachable(u string) bool {
res, err := http.Head(u)
if err != nil {
return false
}
return res.StatusCode == 200
}
我的代码似乎可以工作,但我觉得我错过了一些东西(或者至少它可以更好)。我有几个顾虑/问题:
range
。另外,我不能轻易地将一些done
消息发送到另一个频道,因为我不知道每个何时结束。此频道上的范围
的每个都被阻塞,因此应用程序正在恢复同步
您可以使用信号量来约束并发性。这仍然会产生“1000个goroutine”,但可以确保在给定的时间内只有5个http请求在运行。您可以更改
maxpallel
的值以增加或减少并行请求的数量
func链接(u*url.url,d*goquery.Document)(links[]models.Link){
wg:=sync.WaitGroup{}
linkChan:=make(chan models.Link)
doneChan:=make(chan结构{})
maxParallel:=5
信号量:=make(chan结构{},maxParallel)
d、 查找(“a[href]”。每个(func(index int,item*goquery.Selection){
工作组.添加(1)
go func(){
信号量使用工作池:。尽管1000个goroutine并不特别多,但您也可以将结果写入一个片段中:您不能调用wg.Add(1)
在goroutine中。你在go例程中添加一个切片,切片不是线程安全的。@cojoj:是的,类似于网络请求的东西会使这一点变得合理,但1000个并发网络请求可能不是最有效地利用网络资源的方法。请看所有的工作池示例(或使用信号量)。@JimB您完全可以在goroutine中调用wg.Add(1)
。它是线程安全的。我想您只是想避免在goroutine中调用它,因为第一个wg.Add(1)
可能在wg.Wait()之后调用
。它看起来很不错,但是这个函数从不返回。我在您的示例中将break
更改为return
,它似乎按预期工作。@cojoj我在第一次发布后进行了编辑,您是否使用doneChan运行该版本?哦,没错,它只是脱离了选择,我会将其更新为return
有几种方法可以做到这一点,但linkChan没有缓冲(它是大小为0的通道),因此如果不将wg.Wait()放在goroutine中并开始在select中排空linkChan,执行将只在linkChan处阻塞