如何限制 Goroutine 的数量

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

how to limit goroutine

问题

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

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

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

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

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

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

ch := make(chan label.Label)

for _, l := range r.Labels {
    go func(gmailLabels *gmailclient.Label, gClient *gmail.Client, ch chan<- label.Label) {
        d, err := s.gClient.Service.Users.Labels.Get(s.gClient.User, l.Id).Do()
        if err != nil {
            panic(err)
        }
        // 对标签 `d` 执行一些操作
        preparedLabel := ....
        ch <- preparedLabel
    }(l, s.gClient, ch)
}

for i := 0; i < len(r.Labels); i++ {
    lab := <-ch
    fmt.Printf("Processed %v\n", lab.LabelID)
}

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

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

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

Then, for every label I need to get details

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

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

ch := make(chan label.Label)

for _, l := range r.Labels {

	go func(gmailLabels *gmailclient.Label, gClient *gmail.Client, ch chan&lt;- label.Label) {

		d, err := s.gClient.Service.Users.Labels.Get(s.gClient.User, l.Id).Do()

		if err != nil {
			panic(err)
		}

        // Performs some operation with the label `d`
        preparedLabel := ....

		ch &lt;- preparedLabel

	}(l, s.gClient, ch)
}

for i := 0; i &lt; len(r.Labels); i++ {
	lab := &lt;-ch
	fmt.Printf(&quot;Processed %v\n&quot;, lab.LabelID)
}

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

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中,通道具有小缓冲区以减少同步时间。

chIn := make(chan label.Label, 20)
chOut := make(chan label.Label, 20)

for i := 0; i < 10; i++ {
	go func(gClient *gmail.Client, chIn chan label.Label, chOut chan<- label.Label) {

		for gmailLabels := range chIn {
			d, err := s.gClient.Service.Users.Labels.Get(s.gClient.User, l.Id).Do()

			if err != nil {
				panic(err)
			}

			// 对标签 `d` 执行一些操作
			preparedLabel := ....

			chOut <- preparedLabel

		}

	}(s.gClient, chIn, chOut)

}

go func(chIn chan label.Label) {
	defer close(chIn)
	for _, l := range r.Labels {
		chIn <- l
	}
}(chIn)

for i := 0; i < len(r.Labels); i++ {
	lab := <-chOut
	fmt.Printf("Processed %v\n", lab.LabelID)
}

编辑

这里是一个[playground示例](https://play.golang.org/p/R4b296QOrk)。

<details>
<summary>英文:</summary>

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.

	chIn := make(chan label.Label, 20)
	chOut := make(chan label.Label, 20)

	for i:=0;i&lt;10;i++ {
		go func(gClient *gmail.Client, chIn chan label.Label, chOut chan&lt;- label.Label) {

			for gmailLabels := range chIn {
				d, err := s.gClient.Service.Users.Labels.Get(s.gClient.User, l.Id).Do()

				if err != nil {
					panic(err)
				}

				// Performs some operation with the label `d`
				preparedLabel := ....

				chOut &lt;- preparedLabel

			}

		}(s.gClient, chIn, chOut)

	}

	go func(chIn chan label.Label) {
		defer close(chIn)
		for _, l := range r.Labels {
			chIn &lt;- l
		}
	}(chIn)

	for i := 0; i &lt; len(r.Labels); i++ {
		lab := &lt;-chOut
		fmt.Printf(&quot;Processed %v\n&quot;, lab.LabelID)
	}

EDIT:

Here a [playground sample](https://play.golang.org/p/R4b296QOrk).

</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:

确定