Golang每分钟限制速率

huangapple go评论68阅读模式
英文:

golang rate limit per minute

问题

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

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

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

for {
    limiter.Wait()
    //更多代码
}

这段代码并不能实现预期的效果。它只允许在第一分钟内发送20个请求,然后每分钟只允许发送1个请求。预期的效果是在第一分钟内发送20个请求(不需要均匀分布,比如每3秒1个请求),然后在第二分钟再发送20个请求。在任何1分钟的时间间隔内,不能发送超过20个请求。

你可以参考我的解决方案:https://stackoverflow.com/a/72452542

英文:

How to rate limit 20 requests per minute?

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

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

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

This does not work. What that does is, it allows first 20 requests, then only allows 1 request per minute. What is expected is 20 requests on the first minute(Need not be evenly spread like 1 per 3 seconds) and then 20 more requests on the second minute. At any 1 minute interval, there cannot be more than 20 requests sent.

My solution: https://stackoverflow.com/a/72452542

答案1

得分: 5

设置您期望的速率:

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

for {
    limiter.Wait()
    //更多代码
}

playground链接: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 {
        // 如果计数器达到0:阻塞直到下一个tick
        if l.count <= 0 {
            <-l.ticker.C
            l.count = l.maxCount
        }

        // 否则:
        // 每次在通道上发送一条消息时,将“count”减少一次,
        // 当ticker发出信号时,将“count”重置为“maxCount”
        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

英文:

Set the rate you expect :

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

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

playground: https://go.dev/play/p/ZpxpHj0vK7P


You seem to look for something that allows "bursts of up to 20, reset every minute". Here is a go at it :

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 &lt;= 0 {
			&lt;-l.ticker.C
			l.count = l.maxCount
		}

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

		case &lt;-l.ticker.C:
			l.count = l.maxCount
		}
	}
}

func (l *Limiter) Wait() {
	&lt;-l.ch
}

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

	return l
}

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

答案2

得分: 1

你可以像这样使用time.Tickfor-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
}
英文:

you can use time.Tick and for-select like this:

package main

import (
	&quot;fmt&quot;
	&quot;time&quot;
)

func main() {
	max := 20

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

	exit := make(chan struct{})

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

	&lt;-exit
}

答案3

得分: 0

请尝试以下代码:

import (
	"fmt"
	"time"
)

func main() {
	limiter := time.Tick(3 * time.Minute) // 从20改为3,因为我意识到你想要每分钟20个请求,而不是每20分钟1个请求

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

我实际上没有尝试过20 * time.Minute作为值,但我尝试了200 * time.Millisecond,它可以正常工作。这是我的响应:

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
英文:

try this

import (
	&quot;fmt&quot;
	&quot;time&quot;
)

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 {
		&lt;-limiter
		fmt.Println(time.Now())
	}
}

I haven't actually tried with 20 * time.Minute as the value, but I tried 200 * time.Milisecond and it worked. Here was my response

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

答案4

得分: 0

我的翻译如下:

我的解决方案

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

希望对你有帮助!

英文:

My solution

import (
        &quot;sync&quot;
        &quot;time&quot;
)

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 &amp;l
}
func (l *limiter) Wait() {
        l.mutex.Lock()
        defer l.mutex.Unlock()
        last := &amp;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
        }
}

huangapple
  • 本文由 发表于 2022年5月31日 11:02:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/72441829.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定