简体   繁体   English

无法抓住我的头在 go 率 package

[英]Unable to grasp my head around go rate package

I need to rate-limit the requests to an API and I'm considering using the native golang.org/x/time/rate package for that purpose.我需要对 API 的请求进行速率限制,并且我正在考虑为此目的使用本机golang.org/x/time/rate package。 In order to fiddling a little bit with its API and make sure that my assumptions are correct, I've created this tests, but it definitely seems that I'm missing something here:为了稍微摆弄一下它的 API 并确保我的假设是正确的,我创建了这个测试,但似乎我在这里遗漏了一些东西:

package main

import (
    "github.com/stretchr/testify/require"
    "golang.org/x/time/rate"
    "sync"
    "testing"
)

func TestLimiter(t *testing.T) {
    limiter := rate.NewLimiter(rate.Limit(5),1)
    wg := sync.WaitGroup{}
    successful := 0

    for i:=1; i<=10; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            if limiter.Allow() {
                successful++
            }
        }()
    }
    wg.Wait()

    require.Equal(t, 5, successful)
    
    // This test fails with
    // Expected :5
    // Actual   :1
}

Could someone explain me why is this?有人可以解释一下为什么会这样吗? Shouldn't the rate limiter allow 5 req/s?速率限制器不应该允许 5 req/s 吗?

First, you have a data race.首先,你有一个数据竞赛。 Multiple goroutines write successful without synchronization: undefined behavior.多个 goroutine 在没有同步的情况下successful写入:未定义的行为。

You may use the sync/atomic package for an easy and safe counting:您可以使用sync/atomic package 进行简单安全的计数:

limiter := rate.NewLimiter(rate.Limit(5), 1)
wg := sync.WaitGroup{}
successful := int32(0)

for i := 1; i <= 10; i++ {
    wg.Add(1)
    go func() {
        defer wg.Done()
        if limiter.Allow() {
            atomic.AddInt32(&successful, 1)
        }
    }()
}
wg.Wait()

fmt.Println(successful)

This will output:这将 output:

1

Why?为什么? Because you allow 5 events per second, that's 1 event per 0.2 seconds.因为您每秒允许 5 个事件,所以每 0.2 秒有 1 个事件。 Launching 10 goroutines and checking will take less than 0.2 seconds, so only one event will be allowed.启动 10 个 goroutine 并检查将花费不到 0.2 秒,因此只允许一个事件。

If you add 200 ms sleep in the loop, then all will be allowed and output will be 10 :如果您在循环中添加 200 ms 睡眠,则所有内容都将被允许,并且 output 将为10

for i := 1; i <= 10; i++ {
    time.Sleep(200 * time.Millisecond)
    wg.Add(1)
    go func() {
        defer wg.Done()
        if limiter.Allow() {
            atomic.AddInt32(&successful, 1)
        }
    }()
}

If you add 100 ms sleep, then on average half of them will be allowed and output will be 5 .如果添加 100 ms 睡眠,则平均允许其中一半, output 将为5

What you want probably is allow a burst of 5 with 5 events/sec:您想要的可能是允许 5 次突发 5 个事件/秒:

limiter := rate.NewLimiter(rate.Limit(5), 5)

Using this limiter without sleep, you'll also get an output of 5 .在没有睡眠的情况下使用此limiter ,您还将获得5的 output 。 That's because 5 events are allowed without hitting the rate limit, and without sleep the rest will not be allowed.这是因为在没有达到速率限制的情况下允许 5 个事件,并且在没有睡眠的情况下不允许 rest。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM