在线文档 > Golang练习 > 速率限制
速率限制,是控制资源利用和维护服务质量的重要机制。Go使用协程、通道和定时器优雅地支持速率限制。
package main
import (
"fmt"
"time"
)
func main() {
// 首先我们来看基本的速率限制。
// 假设我们想限制对传入请求的处理,我们将从同名的通道中服务这些请求。
requests := make(chan int, 5)
for i := 1; i <= 5; i++ {
requests <- i
}
close(requests)
// 这个 `limiter` 通道每200毫秒接收一个值。这是我们速率限制方案中的调节器。
limiter := time.Tick(200 * time.Millisecond)
// 通过在每个请求之前从 `limiter` 通道接收来阻塞,我们将自己限制为每200毫秒处理1个请求。
for req := range requests {
<-limiter
fmt.Println("request", req, time.Now())
}
// 我们可能希望在保持整体速率限制的情况下允许短时间突发请求。
// 我们可以通过缓冲速率限制器通道来实现这一点。
// 这个 `burstyLimiter` 通道将允许最多3个事件的突发。
burstyLimiter := make(chan time.Time, 3)
// 填满通道以表示允许的突发。
for i := 0; i < 3; i++ {
burstyLimiter <- time.Now()
}
// 每200毫秒,我们将尝试向 `burstyLimiter` 添加一个新值,最多达到3个。
go func() {
for t := range time.Tick(200 * time.Millisecond) {
burstyLimiter <- t
}
}()
// 现在模拟5个更多的传入请求。其中前3个将受益于 `burstyLimiter` 的突发能力。
burstyRequests := make(chan int, 5)
for i := 1; i <= 5; i++ {
burstyRequests <- i
}
close(burstyRequests)
for req := range burstyRequests {
<-burstyLimiter
fmt.Println("request", req, time.Now())
}
}
运行结果如下:
#运行我们的程序,我们看到第一批请求根据需要每 ~200 毫秒处理一次。
$ go run rate-limiting.go
request 1 2012-10-19 00:38:18.687438 +0000 UTC
request 2 2012-10-19 00:38:18.887471 +0000 UTC
request 3 2012-10-19 00:38:19.087238 +0000 UTC
request 4 2012-10-19 00:38:19.287338 +0000 UTC
request 5 2012-10-19 00:38:19.487331 +0000 UTC
#对于第二批请求,由于可突发的速率限制,我们立即为前 3 个请求提供服务,然后为剩余的 2 个请求提供服务,每个请求延迟 ~200 毫秒。
request 1 2012-10-19 00:38:20.487578 +0000 UTC
request 2 2012-10-19 00:38:20.487645 +0000 UTC
request 3 2012-10-19 00:38:20.487676 +0000 UTC
request 4 2012-10-19 00:38:20.687483 +0000 UTC
request 5 2012-10-19 00:38:20.887542 +0000 UTC