英文:
How to design goroutines program to handle api limit error
问题
刚开始学习关于goroutines的强大之处。
我有大约100个账户和10个地区,通过循环遍历它们,使用golang创建大约1000个goroutines来增加读取速度。它运行得太快了,以至于达到了每秒20次的API返回限制。
我该如何确保所有的goroutines都能以最大的调用速率(20/s)维持?我不确定哪种golang并发方法最适合一起处理错误。
例如:
func readInstance(acc string, region string, wg *sync.WaitGroup) {
    defer wg.Done()
    response, err := client.DescribeInstances(acc, region)
    if err != nil {
        log.Println(err) // API limit exceeding 20
        return
    }
    .
    .
    .
    .
}
func main() {
    accounts := []string{"g", "h", "i", ...}
    regions := []string{"g", "h", "i", ...}
    for _, region := range regions {
        for i := 0; i < len(accounts); i++ {
            wg.Add(1)
            go readInstance(accounts[i], region, &wg)
        }
    }
    wg.Wait()
}
英文:
Just started learning about the power of goroutines.
I have ~100 accounts and ~10 regions, looping through them to create ~ 1000 goroutines with golang to increase the reading speed. It worked too fast that it hit the API return limit of 20/ sec.
How do I ensure that all the goroutines can maintain at the maximum call rate of (20/s)? Im unsure of which golang concurrency methods works best together to handle the error.
eg:
func readInstance(acc string, region string, wg *sync.WaitGroup) {
    defer wg.Done()
    response, err := client.DescribeInstances(acc, region)
    if err != nil {
		log.Println(err) // API limit exceeding 20
		return
	}
    .
    .
    .
    .
}
func main() {
    accounts := []string{"g", "h", "i", ...}
    regions := []string{"g", "h", "i", ...}
	for _, region := range regions {
		for i := 0; i < len(accounts); i++ {
			wg.Add(1)
			go readInstance(accounts[i], region, &wg)
		}
	}
	wg.Wait()
}
答案1
得分: 3
如果您对在特定实际时间内可以进行的请求数量有一个固定的上限,您可以使用time.NewTicker()来间隔请求。
c := time.NewTicker(50 * time.Millisecond)
defer c.Stop()
现在,当您想要进行服务器请求时,只需在实际请求之前插入
<- c.C
即可。
英文:
If you have a fixed upper limit on how many requests you can do in a particular amount of real time, you can use a time.NewTicker() to space things out.
c := time.NewTicker(50 * time.Millisecond)
defer c.Stop()
Now, when you want to make a server request, just insert
<- c.C
prior to the actual request.
答案2
得分: 0
我认为你可以尝试使用这个:https://github.com/uber-go/ratelimit
根据文档,它是并发安全的。
import (
	"fmt"
	"time"
	"go.uber.org/ratelimit"
)
func main() {
    rl := ratelimit.New(100) // 每秒限制100个请求
    prev := time.Now()
    for i := 0; i < 10; i++ {
        now := rl.Take()
        fmt.Println(i, now.Sub(prev))
        prev = now
    }
    // 输出:
    // 0 0
    // 1 10ms
    // 2 10ms
    // 3 10ms
    // 4 10ms
    // 5 10ms
    // 6 10ms
    // 7 10ms
    // 8 10ms
    // 9 10ms
}
英文:
i think you can try this: https://github.com/uber-go/ratelimit
According to the documentation, it is concurrency safe.
import (
	"fmt"
	"time"
	"go.uber.org/ratelimit"
)
func main() {
    rl := ratelimit.New(100) // per second
    prev := time.Now()
    for i := 0; i < 10; i++ {
        now := rl.Take()
        fmt.Println(i, now.Sub(prev))
        prev = now
    }
    // Output:
    // 0 0
    // 1 10ms
    // 2 10ms
    // 3 10ms
    // 4 10ms
    // 5 10ms
    // 6 10ms
    // 7 10ms
    // 8 10ms
    // 9 10ms
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论