如何限制 Goroutine 的数量

huangapple go评论129阅读模式
英文:

how to limit goroutine

问题

我正在开发一个基于Google API的Gmail客户端。

我通过以下调用获取了标签列表:

  1. r, err := s.gClient.Service.Users.Labels.List(s.gClient.User).Do()

然后,对于每个标签,我需要获取详细信息:

  1. for _, l := range r.Labels {
  2. d, err := s.gClient.Service.Users.Labels.Get(s.gClient.User, l.Id).Do()
  3. }

我希望以更强大的方式处理循环,所以我在循环中实现了一个goroutine:

  1. ch := make(chan label.Label)
  2. for _, l := range r.Labels {
  3. go func(gmailLabels *gmailclient.Label, gClient *gmail.Client, ch chan<- label.Label) {
  4. d, err := s.gClient.Service.Users.Labels.Get(s.gClient.User, l.Id).Do()
  5. if err != nil {
  6. panic(err)
  7. }
  8. // 对标签 `d` 执行一些操作
  9. preparedLabel := ....
  10. ch <- preparedLabel
  11. }(l, s.gClient, ch)
  12. }
  13. for i := 0; i < len(r.Labels); i++ {
  14. lab := <-ch
  15. fmt.Printf("Processed %v\n", lab.LabelID)
  16. }

这段代码的问题是Gmail API有一个速率限制,所以我会得到以下错误:

  1. panic: googleapi: Error 429: Too many concurrent requests for user, rateLimitExceeded

如何正确处理这种情况?

英文:

I'm developing a gmail client based on google api.

I have a list of labels obtained through this call

  1. r, err := s.gClient.Service.Users.Labels.List(s.gClient.User).Do()

Then, for every label I need to get details

  1. for _, l := range r.Labels {
  2. d, err := s.gClient.Service.Users.Labels.Get(s.gClient.User, l.Id).Do()
  3. }

I'd like to handle the loop in a more powerful way so I have implemented a goroutine in the loop:

  1. ch := make(chan label.Label)
  2. for _, l := range r.Labels {
  3. go func(gmailLabels *gmailclient.Label, gClient *gmail.Client, ch chan&lt;- label.Label) {
  4. d, err := s.gClient.Service.Users.Labels.Get(s.gClient.User, l.Id).Do()
  5. if err != nil {
  6. panic(err)
  7. }
  8. // Performs some operation with the label `d`
  9. preparedLabel := ....
  10. ch &lt;- preparedLabel
  11. }(l, s.gClient, ch)
  12. }
  13. for i := 0; i &lt; len(r.Labels); i++ {
  14. lab := &lt;-ch
  15. fmt.Printf(&quot;Processed %v\n&quot;, lab.LabelID)
  16. }

The problem with this code is that gmail api has a rate limit, so, I get this error:

  1. panic: googleapi: Error 429: Too many concurrent requests for user, rateLimitExceeded

What is the correct way to handle this situation?

答案1

得分: 1

只启动10个goroutine,然后在一个goroutine中从一个for循环传递值到另一个goroutine中,通道具有小缓冲区以减少同步时间。

  1. chIn := make(chan label.Label, 20)
  2. chOut := make(chan label.Label, 20)
  3. for i := 0; i < 10; i++ {
  4. go func(gClient *gmail.Client, chIn chan label.Label, chOut chan<- label.Label) {
  5. for gmailLabels := range chIn {
  6. d, err := s.gClient.Service.Users.Labels.Get(s.gClient.User, l.Id).Do()
  7. if err != nil {
  8. panic(err)
  9. }
  10. // 对标签 `d` 执行一些操作
  11. preparedLabel := ....
  12. chOut <- preparedLabel
  13. }
  14. }(s.gClient, chIn, chOut)
  15. }
  16. go func(chIn chan label.Label) {
  17. defer close(chIn)
  18. for _, l := range r.Labels {
  19. chIn <- l
  20. }
  21. }(chIn)
  22. for i := 0; i < len(r.Labels); i++ {
  23. lab := <-chOut
  24. fmt.Printf("Processed %v\n", lab.LabelID)
  25. }
  26. 编辑
  27. 这里是一个[playground示例](https://play.golang.org/p/R4b296QOrk)。
  28. <details>
  29. <summary>英文:</summary>
  30. How about only starting e.g. 10 goroutines and pass the values in from one for loop in another go routine. The channels have a small buffer to decrease synchronisation time.
  31. chIn := make(chan label.Label, 20)
  32. chOut := make(chan label.Label, 20)
  33. for i:=0;i&lt;10;i++ {
  34. go func(gClient *gmail.Client, chIn chan label.Label, chOut chan&lt;- label.Label) {
  35. for gmailLabels := range chIn {
  36. d, err := s.gClient.Service.Users.Labels.Get(s.gClient.User, l.Id).Do()
  37. if err != nil {
  38. panic(err)
  39. }
  40. // Performs some operation with the label `d`
  41. preparedLabel := ....
  42. chOut &lt;- preparedLabel
  43. }
  44. }(s.gClient, chIn, chOut)
  45. }
  46. go func(chIn chan label.Label) {
  47. defer close(chIn)
  48. for _, l := range r.Labels {
  49. chIn &lt;- l
  50. }
  51. }(chIn)
  52. for i := 0; i &lt; len(r.Labels); i++ {
  53. lab := &lt;-chOut
  54. fmt.Printf(&quot;Processed %v\n&quot;, lab.LabelID)
  55. }
  56. EDIT:
  57. Here a [playground sample](https://play.golang.org/p/R4b296QOrk).
  58. </details>

huangapple
  • 本文由 发表于 2017年8月7日 17:54:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/45544133.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定