2017-11-11 208 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