For loop 暂停for循环的执行

For loop 暂停for循环的执行,for-loop,go,For Loop,Go,我有一个API,我也发布了一个小的JSON对象 这是一个无限循环,循环7种颜色(彩虹),并将这些颜色发送到前面提到的JSON对象中 我连接的API的速率限制为每分钟40个请求 我不想达到利率上限,因此我设计了一种方法来避免这种情况 我有一个全局变量,用于存储允许发出的请求数 我有一个函数,它保存一个每60秒运行一次的ticker设置,并将存储我的请求的全局变量加满 然后我有一个永无止境的for循环,它运行并检查仍然允许发出的请求数,如果它大于0,则我们发出下一个请求,如果不是,则我们只需睡眠一

我有一个API,我也发布了一个小的JSON对象

这是一个无限循环,循环7种颜色(彩虹),并将这些颜色发送到前面提到的JSON对象中

我连接的API的速率限制为每分钟40个请求

我不想达到利率上限,因此我设计了一种方法来避免这种情况

  • 我有一个全局变量,用于存储允许发出的请求数
  • 我有一个函数,它保存一个每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
包。除此之外,用你的完整代码发布一个问题。啊-就是这样!我让这个工作,我很喜欢它!我真的很喜欢客户端本身存在的限制。感谢分享此解决方案。