创建一个同步速率限制器

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

Creating a Synchronous Rate Limiter

问题

我正在模拟一个请求过程,其中我有一个同步速率限制器(以通道的形式,cap == 要限制的项目数)。期望的速率限制是每秒1个请求。

我认为问题在于我正在使用一个阻塞的for而不是一个goroutine,但是我期望的目标是以同步的方式模拟这个过程。

我希望在执行操作时通知我的通道(在我的代码示例中的打印语句),并且直到操作完成为止。我希望确保如果操作在<1秒内成功完成,我会等待差异直到发送下一个for迭代。

也许通道有些过度,因为我这里没有使用goroutine,我应该在每次迭代开始时和每次接收到响应后进行一些时间测量,然后使用time.Sleep()等待差异?有更好的方法吗?

package main

import (
	"fmt"
	"time"
)

type Data struct {
	Field1 string
	Ch     chan struct{}
}

func main() {
	data := &Data{
		Field1: "hello world",
		Ch:     make(chan struct{}, 1),
	}

	// 填充我们的数据通道桶
	for i := 0; i < cap(data.Ch); i++ {
		data.Ch <- struct{}{}
	}
	defer close(data.Ch)

	// 创建goroutine,每1秒尝试执行一次操作
	go func() {
		ticker := time.NewTicker(1 * time.Second)
		defer ticker.Stop()
		for range ticker.C {
			_, ok := <-data.Ch
			if !ok {
				return
			}
		}
	}()

	count := 0
	for {
		if count == 10 {
			fmt.Println("打破循环!")
			break
		}

		// 将令牌放入通道中,表示我们正在执行一个操作
		data.Ch <- struct{}{}

		// 做一些事情
		fmt.Printf("你好用户!现在是:%s\n", time.Now().UTC().Format("2006-01-02T15:04:05.000Z07:00"))

		// 从通道中移除令牌,以便我们可以执行更多操作
		<-data.Ch
		count++
	}
}
英文:

I am emulating a request process where I have a synchronous rate limiter (in the form of a channel with cap == number of items to be limited on). The desired rate limit is 1 request per 1 second.

The issue I believe is that I am using a blocking for and not a goroutine, however my desired goal is to emulate this process synchronously.

I desire that I notify my channel that an operation is being performed (the print statement in my code example), and until that is complete and finished. I'd like to make sure that if the operation succeeded in < 1 second. I wait the difference until I send the next for iteration.

Perhaps a channel is overkill since I'm not using goroutines here and I should do some time measuring at the start of each iteration and after each response is received to time.Sleep() for the difference? Is there a better way?

package main

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

type Data struct {
	Field1 string
	Ch     chan struct{}
}

func main() {
	data := &amp;Data{
		Field1: &quot;hello world&quot;,
		Ch:     make(chan struct{}, 1),
	}

	// fill up our data channel bucket
	for i := 0; i &lt; cap(data.Ch); i++ {
		data.Ch &lt;- struct{}{}
	}
	defer close(data.Ch)

	// create goroutine to attempt to do something every 1 second
	go func() {
		ticker := time.NewTicker(1 * time.Second)
		defer ticker.Stop()
		for range ticker.C {
			_, ok := &lt;-data.Ch
			if !ok {
				return
			}
		}
	}()

	count := 0
	for {
		if count == 10 {
			fmt.Println(&quot;breaking the loop!&quot;)
			break
		}

		// place token into channel to signal we are performing an operation
		data.Ch &lt;- struct{}{}

		// do things
		fmt.Printf(&quot;hello user! it is: %s o clock!\n&quot;, time.Now().UTC().Format(&quot;2006-01-02T15:04:05.000Z07:00&quot;))

		// remove token in channel so we can do more operations
		&lt;-data.Ch
		count++
	}
}

答案1

得分: 1

你似乎在做反向操作。如果你想要一个简单的速率限制器,可以使用一个通道,然后创建一个 goroutine 以给定的速率填充该通道:

go func() {
        ticker := time.NewTicker(1 * time.Second)
        defer ticker.Stop()
        for range ticker.C {
            select {
             case data.Ch<-struct{}{}:
             default:
            }
        }
}()

然后,从通道中消费数据以进行速率限制:

for {
  <-data.Ch
  // 做一些操作
}
英文:

You seem to be doing this backwards. If you want a simple rate limiter using a channel, then have a goroutine that fills the channel at a given rate:

go func() {
        ticker := time.NewTicker(1 * time.Second)
        defer ticker.Stop()
        for range ticker.C {
            select {
             case data.Ch&lt;-struct{}{}:
             default:
            }
        }
}()

Then, consume from the channel to rate limit:

for {
  &lt;-data.Ch
  // Do stuff
}

huangapple
  • 本文由 发表于 2023年4月11日 05:04:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/75980720.html
匿名

发表评论

匿名网友

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

确定