[英]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.