For loop 暂停for循环的执行
我有一个API,我也发布了一个小的JSON对象 这是一个无限循环,循环7种颜色(彩虹),并将这些颜色发送到前面提到的JSON对象中 我连接的API的速率限制为每分钟40个请求 我不想达到利率上限,因此我设计了一种方法来避免这种情况For loop 暂停for循环的执行,for-loop,go,For Loop,Go,我有一个API,我也发布了一个小的JSON对象 这是一个无限循环,循环7种颜色(彩虹),并将这些颜色发送到前面提到的JSON对象中 我连接的API的速率限制为每分钟40个请求 我不想达到利率上限,因此我设计了一种方法来避免这种情况 我有一个全局变量,用于存储允许发出的请求数 我有一个函数,它保存一个每60秒运行一次的ticker设置,并将存储我的请求的全局变量加满 然后我有一个永无止境的for循环,它运行并检查仍然允许发出的请求数,如果它大于0,则我们发出下一个请求,如果不是,则我们只需睡眠一
- 我有一个全局变量,用于存储允许发出的请求数
- 我有一个函数,它保存一个每60秒运行一次的ticker设置,并将存储我的请求的全局变量加满
- 然后我有一个永无止境的for循环,它运行并检查仍然允许发出的请求数,如果它大于0,则我们发出下一个请求,如果不是,则我们只需睡眠一秒钟,然后重试
var rateLimit int
func main() {
request := gorequest.New().SetDebug(false)
// Set the initial request bucket to 40
rateLimit = 40
go topUpLimiter()
for {
makeTheLightsBlinkTheRainbow(request)
}
}
func topUpLimiter() {
for range time.Tick(60 * time.Second) {
rateLimit += 40
}
}
func makeTheLightsBlinkTheRainbow(request *gorequest.SuperAgent) {
colours := [7]string{"red", "orange", "yellow", "green", "blue", "purple", "pink"}
for _, colour := range colours {
if rateLimit > 0 {
response, _, _ := request.Post("http://example.com/blink").
Send(fmt.Sprintf(`{"color":"%v"}`, colour)).
End()
rateLimit--
} else {
time.Sleep(1 * time.Second)
}
}
}
这是可行的,我从来没有达到过速率限制,但一旦请求用完,循环将继续运行,并且只有在rateLimit
变量加满时才会再次开始发出请求
我正在使一个物联网灯闪烁彩虹的颜色,结果是一旦rateLimit
变量用完,颜色就会出现问题,然后由于for循环一直在运行,随后会加满
我想在等待rateLimit
变量补充时暂停/阻止for循环,这样颜色就不会出现问题
我将如何实现这样的东西?从我的搜索结果来看,这似乎是可能的渠道,但我不太确定如何做到这一点
这是一个最终会发生什么的例子:
一旦它运行完毕,您会注意到打印出来的颜色在大约运行到一半时出现了问题。尝试更改为
func makeTheLightsBlinkTheRainbow(request *gorequest.SuperAgent) {
colours := [7]string{"red", "orange", "yellow", "green", "blue", "purple", "pink"}
i := 0
for {
if rateLimit > 0 {
response, _, _ := request.Post("http://example.com/blink").
Send(fmt.Sprintf(`{"color":"%v"}`, colours[i])).
End()
i = (i+1) % 7
rateLimit--
} else {
time.Sleep(1 * time.Second)
}
}
}
我的建议是:采取完全不同的方法来限制利率 我会把它放在HTTP传输中,因为在逻辑上应该存在这样的限制,这样就根本不需要修改应用程序代码。比如:
import (
"net/http"
"golang.org/x/time/rate"
)
type rateLimitTransport struct {
limiter *rate.Limiter
xport http.RoundTripper
}
var _ http.RoundTripper = &rateLimitTransport{}
func newRateLimitTransport(r float64, xport http.RoundTripper) http.RoundTripper {
return &rateLimitTransport{
limiter: rate.NewLimiter(rate.Limit(r), 1),
xport: xport,
}
}
func (t *rateLimitTransport) RoundTrip(r *http.Request) (*http.Response, error) {
t.limiter.Wait(r.Context())
return t.xport.RoundTrip(r)
}
这使用golang.org/x/time/rate
包来实现利率限制newRateLimitTransport()
创建一个新的速率限制传输,其中r
是每秒允许的最大请求数
要利用这一点,请在后端API的HTTP客户端中使用速率限制传输的实例:
// set this in `init()` for example
myClient := http.&Client{
// Use a rate-limiting transport which falls back to the default
Transport: newRateLimitTransport(60, http.DefaultTransport)
}
// Then later use `myClient` instead of the default, when making API
// requests:
req, err := http.NewRequest(http.MethodPost, url, body)
if err != nil {
return err
}
myClient.Do(req)
你看过关于利率限制的维基文章了吗?我没有——尽管看起来很有希望。我现在就来试试实现它。@Peter您如何将它环绕在颜色的for循环上,以便使颜色按顺序发送?无论您使用什么来限制速率,您都不应该在颜色上循环。相反,当您准备发送请求时,查找您这次需要发送的颜色。这是一个XY问题。更好的方法是一种不同的速率限制方法。这看起来很酷-我如何将其限制为每分钟20个请求。我在查看如何将其从每秒x个请求更改为0.33个请求时遇到了一些问题。
newRateLimitTransport(0.33,http.DefaultTransport)
将限制为每秒0.33个请求=每分钟20个。好的,这是有意义的。我已经实现了这一点,但在尝试运行它时遇到一个错误:undefined:rate in rate.Limiter
,它源于ratelimitransport
结构。有没有办法解决这个问题?@James:导入rate
包。除此之外,用你的完整代码发布一个问题。啊-就是这样!我让这个工作,我很喜欢它!我真的很喜欢客户端本身存在的限制。感谢分享此解决方案。