golang 速率限制每分钟

IT小君   2022-11-10T23:58:12

如何限制每分钟 20 个请求?

import "golang.org/x/time/rate"

limiter := rate.NewLimiter(rate.Every(1*time.Minute), 20)

for {
    limiter.Wait()
    //more code
}

这不起作用。这样做的是,它允许前 20 个请求,然后每分钟只允许 1 个请求。预计第一分钟有 20 个请求(不需要像每 3 秒 1 个那样均匀分布),然后第二分钟再有 20 个请求。在任何 1 分钟间隔内,发送的请求不能超过 20 个。

我的解决方案:https ://stackoverflow.com/a/72452542

点击广告,支持我们为你提供更好的服务
评论(4)
IT小君

设置您期望的速率:

limiter := rate.NewLimiter(rate.Every(1*time.Minute/20), 20)

for {
    limiter.Wait()
    //more code
}

游乐场:https ://go.dev/play/p/ZpxpHj0vK7P


您似乎在寻找允许“最多 20 次,每分钟重置一次”的东西。这是一个尝试:

type Limiter struct {
    maxCount int
    count    int
    ticker   *time.Ticker
    ch       chan struct{}
}

func (l *Limiter) run() {
    for {
        // if counter has reached 0: block until next tick
        if l.count <= 0 {
            <-l.ticker.C
            l.count = l.maxCount
        }

        // otherwise:
        // decrement 'count' each time a message is sent on channel,
        // reset 'count' to 'maxCount' when ticker says so
        select {
        case l.ch <- struct{}{}:
            l.count--

        case <-l.ticker.C:
            l.count = l.maxCount
        }
    }
}

func (l *Limiter) Wait() {
    <-l.ch
}

func NewLimiter(d time.Duration, count int) *Limiter {
    l := &Limiter{
        maxCount: count,
        count:    count,
        ticker:   time.NewTicker(d),
        ch:       make(chan struct{}),
    }
    go l.run()

    return l
}

https://go.dev/play/p/5WiOJL5nqCy

2022-11-10T23:58:12   回复
IT小君

尝试这个

import (
    "fmt"
    "time"
)

func main() {
    limiter := time.Tick(3 * time.Minute) //changed from 20 to 3 because i realized you wanted 20 requests per minute, not 1 request per 20 minutes

    for true {
        <-limiter
        fmt.Println(time.Now())
    }
}

我实际上并没有尝试过20 * time.Minute作为值,但我尝试过200 * time.Milisecond并且它有效。这是我的回应

2022-05-31 00:06:13.447108 -0600 MDT m=+0.200889915
2022-05-31 00:06:13.651373 -0600 MDT m=+0.405148283
2022-05-31 00:06:13.851522 -0600 MDT m=+0.605291066
2022-05-31 00:06:14.051481 -0600 MDT m=+0.805244205
2022-05-31 00:06:14.250144 -0600 MDT m=+1.003900790
2022-05-31 00:06:14.450952 -0600 MDT m=+1.204703429
2022-05-31 00:06:14.648365 -0600 MDT m=+1.402110595
2022-05-31 00:06:14.848223 -0600 MDT m=+1.601961982
2022-05-31 00:06:15.04909 -0600 MDT m=+1.802823232
2022-05-31 00:06:15.250164 -0600 MDT m=+2.003891217
2022-11-10T23:58:13   回复
IT小君

你可以像time.Tick这样使用for-select

package main

import (
    "fmt"
    "time"
)

func main() {
    max := 20

    limiter := time.Tick(1 * time.Minute)

    exit := make(chan struct{})

    go func() {
        count := 0
        exit2 := 0
        defer func() {
            exit <- struct{}{}
        }()
        for {
            select {
            case <-limiter:
                count = 0
                fmt.Println("exit2: ", exit2)
                if exit2 == 3 {
                    return
                }
                exit2++
            default:
                if count == max {
                    continue
                }
                fmt.Println("accepting request", count)
                count++
            }
        }
    }()

    <-exit
}
2022-11-10T23:58:13   回复
IT小君

我的解决方案

import (
        "sync"
        "time"
)

type Limiter interface {
        Wait()
}

type limiter struct {
        tick    time.Duration
        count   uint
        entries []time.Time
        index   uint
        mutex   sync.Mutex
}

func NewLimiter(tick time.Duration, count uint) Limiter {
        l := limiter{
                tick:  tick,
                count: count,
                index: 0,
        }
        l.entries = make([]time.Time, count)
        before := time.Now().Add(-2 * tick)
        for i, _ := range l.entries {
                l.entries[i] = before
        }
        return &l
}
func (l *limiter) Wait() {
        l.mutex.Lock()
        defer l.mutex.Unlock()
        last := &l.entries[l.index]
        next := last.Add(l.tick)
        now := time.Now()
        if now.Before(next) {
                time.Sleep(next.Sub(now))
        }
        *last = time.Now()
        l.index = l.index + 1
        if l.index == l.count {
                l.index = 0
        }
}
2022-11-10T23:58:13   回复