Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jquery-ui/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
等待所有goroutine完成并合并结果_Go_Channel_Goroutine_Goquery - Fatal编程技术网

等待所有goroutine完成并合并结果

等待所有goroutine完成并合并结果,go,channel,goroutine,goquery,Go,Channel,Goroutine,Goquery,我很难理解Goroutine、频道和所有同步的东西。我相信我理解这些概念,但我遗漏了几行连接我所有信息的线路。而且,大多数的例子感觉太简单了,所以我不能正确地理解实际发生的事情 我正在为网站编写一个简单的分析工具。其中一个功能是检查是否可以访问此网站上的所有链接。显然,每个网站上都有很多链接,所以它似乎是一个很好的goroutines候选网站。问题是,在安排所有goroutine之后,我需要返回所有结果,以便将它们一次全部呈现给用户 到目前为止,我得到的是: func links(u *url.

我很难理解Goroutine、频道和所有同步的东西。我相信我理解这些概念,但我遗漏了几行连接我所有信息的线路。而且,大多数的例子感觉太简单了,所以我不能正确地理解实际发生的事情

我正在为网站编写一个简单的分析工具。其中一个功能是检查是否可以访问此网站上的所有链接。显然,每个网站上都有很多链接,所以它似乎是一个很好的goroutines候选网站。问题是,在安排所有goroutine之后,我需要返回所有结果,以便将它们一次全部呈现给用户

到目前为止,我得到的是:

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
}
我的代码似乎可以工作,但我觉得我错过了一些东西(或者至少它可以更好)。我有几个顾虑/问题:

  • 如果这个网站包含1000个链接,我会制作1000个goroutines,我相信它不是那么聪明。也许我需要一个员工池或类似的东西,对吗
  • 是否可以仅在本例中使用通道?我不知道会找到多少链接,所以我无法轻松地对发送到频道的元素进行
    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处阻塞