2017-11-11 209 views
1

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

下面是代码:

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) 
     } 
    } 
} 

这里是输出:

┌[ nb-kondrashov: ~/Gitlab/gitlab-auditor ] 
└[ skondrashov ]-> ./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 
................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................ 

每当它的不同的项目,但它的id是大约550

当我试图从输出中扼制链接,我得到正常的JSON。当我试图用queue := make(chan struct{}, 1)(单线程)运行这段代码时 - 一切都很好。

它可能是什么?

+2

尝试限制同时连接的数量。 –

+0

我想在这里做:'queue:= make(chan struct {},N)'(N =连接数),并且它有部分帮助,但是我失去了性能。这是gitlab,golang或我的电脑的问题吗? – sergkondr

+1

我想50是太多了。可能存在某种限制连接数量的DDoS保护。尝试减少,例如5或10. –

回答

1

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

  • 您创建的大小为50

  • 缓冲通道,那么你火了1532个够程

  • 他们的第一个50本身排队并开始处理。当他们< - 排队并释放一些空间时,下一个随机的一个管理员进入队列。

  • 正如人们在评论中所说的那样,当然你在某些限制的范围内遇到了一些限制,比如说550 gitlab的API对你感到愤怒并且限制了速度。

  • 然后另一个够程进行烧制,将关闭通道通知主够程

  • 主够程读取消息。

谈话go concurrency patterns 以及这个博客帖子concurrency in go可能的帮助。 我个人很少使用缓冲频道。你的问题,我会是这样的:

  • 定义多个工人

  • 有主够程火了一个FUNC听INTS的通道上,这样做的API调用,写工人一个项目的渠道

  • 有主要的goroutine发送到一个项目编号的渠道,从项目的渠道中读取和读取。

    • 也许ratelimit通过发射一个代码,并有主读取之前它发送下一个请求?
  • 主要关闭号码通道以通知其他人死亡。

+0

感谢您的回答,特别感谢链接到“去并发模式”。我已经通过限制线程数量并根据Eugene Lisitsky的回答调整Gitlab来解决了这个问题 – sergkondr