首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >尝试使用go例程时无法抓取数据

尝试使用go例程时无法抓取数据
EN

Stack Overflow用户
提问于 2019-06-21 04:41:20
回答 1查看 497关注 0票数 0

我正在尝试为一个给定的单词抓取相关的单词,我使用BFS从这个给定的单词开始,并在dictionary.com上搜索每个相关的单词

我在没有并发的情况下尝试了这段代码,它工作得很好,但是需要花费很多时间,所以我尝试使用go例程,但是我的代码在第一次迭代后就卡住了。第一个级别的BFS运行良好,但是在第二个级别它挂起了!

代码语言:javascript
复制
package main

import (
    "fmt"
    "github.com/gocolly/colly"
    "sync"
)

var wg sync.WaitGroup


func buildURL(word string) string {
    return "https://www.dictionary.com/browse/" + string(word)
}

func get(url string) []string {
    c := colly.NewCollector()
    c.IgnoreRobotsTxt = true
    var ret []string
    c.OnHTML("a.css-cilpq1.e15p0a5t2", func(e *colly.HTMLElement) {
        ret = append(ret, string(e.Text))
    })
    c.Visit(url)
    c.Wait()

    return ret
}

func threading(c chan []string, word string) {
    defer wg.Done()
    var words []string
    for _, w := range get(buildURL(word)) {
        words = append(words, w)
    }
    c <- words
}

func main() {
    fmt.Println("START")
    word := "jump"
    maxDepth := 2

    //bfs
    var q map[string]int
    nq := map[string]int {
        word: 0,
    }

    vis := make(map[string]bool)
    queue := make(chan []string, 5000)

    for i := 1; i <= maxDepth; i++ {
        fmt.Println(i)
        q, nq = nq, make(map[string]int)
        for word := range q {
            if _, ok := vis[word]; !ok {
                wg.Add(1)
                vis[word] = true
                go threading(queue, word)

                for v := range queue {
                    fmt.Println(v)
                    for _, w := range v {
                        nq[w] = i
                    }
                }
            }
        }
    }
    wg.Wait()
    close(queue)
    fmt.Println("END")
}

输出:

代码语言:javascript
复制
START
1
[plunge dive rise upsurge bounce hurdle fall vault drop advance upturn inflation increment spurt boost plummet skip bound surge take]

永远挂在这里,counter =2不打印!

可以在这里查看https://www.dictionary.com/browse/jump中的相关单词。

EN

回答 1

Stack Overflow用户

发布于 2019-06-23 03:44:22

根据Tour of Go的说法

仅当缓冲区已满时,

才会发送到缓冲通道块。当缓冲区为空时接收块。

因此,在本例中,您将创建一个长度为5000的缓冲通道。

代码语言:javascript
复制
for i := 1; i <= maxDepth; i++ {
    fmt.Println(i)
    q, nq = nq, make(map[string]int)
    for word := range q { // for each word
        if _, ok := vis[word]; !ok { // if not visited visit
            wg.Add(1) // add a worker
            vis[word] = true
            go threading(queue, word) // fetch in concurrent manner
            for v := range queue { // <<< blocks here when queue is empty
                fmt.Println(v)
                for _, w := range v {
                    nq[w] = i
                }
            }
        }
    }
}

正如你所看到的,我在代码中做了注释,在第一次迭代之后,for循环将阻塞,直到channel为空。在这种情况下,在获取jump之后,它会向数组发送对应的相似字,但在此之后,由于for循环被阻塞,因为zerkems解释了您将无法进入下一次迭代(i= 2)。您最终可以关闭通道以结束for循环中的阻塞。但是,由于您使用相同的通道来重写多个goroutine,所以如果您从多个goroutines关闭它,它将会崩溃。

为了克服这个问题,我们可以想出一个很好的解决方法。

  1. 我们确切地知道我们正在提取多少未访问的项目。
  2. 我们现在知道block

在哪里

首先,我们需要计算未访问的单词,然后我们可以迭代该时间

代码语言:javascript
复制
    vis := make(map[string]bool)
    queue := make(chan []string, 5000)
    for i := 1; i <= maxDepth; i++ {
        fmt.Println(i)
        q, nq = nq, make(map[string]int)
        unvisited := 0
        for word := range q {
            if _, ok := vis[word]; !ok {
                vis[word] = true
                unvisited++
                wg.Add(1)
                go threading(queue, word)
            }
        }

        wg.Wait() // wait until jobs are done
        for j := 0; j < unvisited; j++ { // << does not block as we know how much
            v := <-queue // we exactly try to get unvisited amount
            fmt.Println(v)
            for _, w := range v {
                nq[w] = i
            }
        }
    }

在这种情况下,我们只是简单地计算获得结果所需的最小迭代次数。另外,您可以看到我已经向下移动了for循环外部,并使用原来的循环仅向worker添加单词。它将要求获取所有的单词,并在接下来的循环中等待,以非阻塞的方式完成这些任务。

后一个循环等待所有工作进程完成。在下一次迭代之后,可以达到works和BFS的下一个级别。

摘要

为results

  • Don't分发
  1. 同时执行这两项操作

希望这能有所帮助。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56693590

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档