我是编程新手,需要帮助。尝试在 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/