multithreading - 通过 golang 进行 gitlab 抓取的问题

标签 multithreading go web-scraping gitlab

我是编程新手,需要帮助。尝试在 golang 上编写 gitlab scraper。 当我试图在多线程模式下获取有关项目的信息时出现问题。

代码如下:

func (g *Gitlab) getAPIResponce(url string, structure interface{}) error {
    responce, responce_error := http.Get(url)
    if responce_error != nil {
        return responce_error
    }
    ret, _ := ioutil.ReadAll(responce.Body)
    if string(ret) != "[]" {
        err := json.Unmarshal(ret, structure)
        return err
    }
    return errors.New(error_emptypage)
}

...

func (g *Gitlab) GetProjects() {
    projects_chan := make(chan Project, g.LatestProjectID) 
    var waitGroup sync.WaitGroup                           
    queue := make(chan struct{}, 50)                                      
    for i := g.LatestProjectID; i > 0; i-- {               
        url := g.BaseURL + projects_url + "/" + strconv.Itoa(i) + g.Token
        waitGroup.Add(1)
        go func(url string, channel chan Project) {
            queue <- struct{}{}
            defer waitGroup.Done()

            var oneProject Project
            err := g.getAPIResponce(url, &oneProject)
            if err != nil {
                fmt.Println(err.Error())
            }

            fmt.Printf(".")
            channel <- oneProject
            <-queue
        }(url, projects_chan)
    }

    go func() {
        waitGroup.Wait()
        close(projects_chan)
    }()

    for project := range projects_chan {
        if project.ID != 0 {
            g.Projects = append(g.Projects, project)
        }
    }
}

这是输出:

$ ./gitlab-auditor 
latest project = 1532
Gathering projects...
.......................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................Get https://gitlab.example.com/api/v4/projects/563&private_token=SeCrEt_ToKeN: unexpected EOF
Get https://gitlab.example.com/api/v4/projects/558&private_token=SeCrEt_ToKeN: unexpected EOF
..Get https://gitlab.example.com/api/v4/projects/531&private_token=SeCrEt_ToKeN: unexpected EOF
Get https://gitlab.example.com/api/v4/projects/571&private_token=SeCrEt_ToKeN: unexpected EOF
.Get https://gitlab.example.com/api/v4/projects/570&private_token=SeCrEt_ToKeN: unexpected EOF
..Get https://gitlab.example.com/api/v4/projects/467&private_token=SeCrEt_ToKeN: unexpected EOF
Get https://gitlab.example.com/api/v4/projects/573&private_token=SeCrEt_ToKeN: unexpected EOF
................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................

每次都是不同的project,但是id都在550左右。

当我试图从输出中 curl 链接时,我得到的是普通的 JSON。当我尝试使用 queue := make(chan struct{}, 1)(在单线程中)运行此代码时 - 一切正常。

它可以是什么?

最佳答案

我会说这不是实现并发的非常明确的方法。 这里似乎发生的是

  • 您创建了一个大小为 50 的缓冲 channel 。

  • 然后启动 1532 个 goroutine

  • 其中的前 50 个自行排队并开始处理。当他们<-排队并释放一些空间时,下一个随机的一个设法进入队列。

  • 正如人们在评论中所说的,当爆炸达到 id 550 左右时,您肯定会遇到一些限制。然后 gitlab 的 API 对您和速率限制感到愤怒。

  • 然后另一个 goroutine 被触发,关闭 channel 通知主 goroutine

  • 主 goroutine 读取消息。

谈话 go concurrency patterns 以及这篇博文 concurrency in go可能有帮助。 我个人很少使用缓冲 channel 。对于你的问题,我会喜欢:

  • 定义多个worker

  • 让 main goroutine 启动 workers,用一个 func 监听一个 int channel ,执行 api 调用,写入一个项目 channel

  • 让主 goroutine 将要从项目 channel 中获取和读取的项目编号发送到一个整数 channel 。

    • 也许可以通过触发一个自动收报机来限制速率,并在它发送下一个请求之前从中读取主要内容?
  • main关闭号码 channel ,通知其他人死亡。

关于multithreading - 通过 golang 进行 gitlab 抓取的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47241535/

相关文章:

C# 静态构造函数在填充 ConcurrentDictionary 时初始化线程安全

c# - 执行期间线程/任务上下文切换

go - 如何在子进程中读取 `exec.Cmd` ExtraFiles fd?

go - 如何在 Ubuntu 中启动 Go 程序作为守护进程?

google-app-engine - 如何根据项目ID设置变量?

python - 使用 scrapy 从 wordpress 站点抓取

c - 线程安全的多文件写入

java - 线程转储被阻止并锁定

python - 如果我有一个except,我该如何重做?

javascript - 使用nodejs抓取完全渲染的网页