暂停执行for循环

时间:2018-02-11 07:01:13

标签: for-loop go

我有一个API,我也在发布一个小JSON对象。

这是一个无限循环,循环超过7种颜色(彩虹)并将它们发送到上述JSON对象中。

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

我不想达到限速,所以我设计了一种方法来避免这种情况;

  • 我有一个全局变量,用于存储我允许的请求数
  • 我有一个函数,它包含一个每60秒运行一次的自动收报机,并充满存储我的请求的全局变量
  • 然后我有一个永无止境的循环运行并检查仍然允许的请求数,如果它大于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变量充满时才会再次开始发出请求。

我正在使IoT灯闪烁彩虹的颜色,结果是一旦rateLimit变量用完后颜色就会失序,然后由于for循环刚好加满了继续跑步。

我希望在等待rateLimit变量补充时暂停/阻止for循环,以便颜色不会出现故障。

我将如何实现类似的东西?从我的搜索来看似乎可能有渠道,但我不太确定如何做到这一点。

这是最终发生的事情的一个例子:https://play.golang.org/p/r6OG4kK9vCP 一旦它完成运行,你会注意到打印出的颜色大约在中途发生故障。

2 个答案:

答案 0 :(得分:1)

我的建议:采取完全不同的方法来限速。

我会把它放在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是每秒允许的最大请求数。

要利用此功能,请在HTTP客户端中为后端API使用速率限制传输的实例:

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

答案 1 :(得分:0)

尝试更改为

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)
        }
    }
}