Go by Example: Rate Limiting速率控制

英文源地址
速率控制式控制资源和保持服务质量的重要机制.Go优雅地支持用goroutine, channel和tickers实现速率限制.

package main

import (
	"fmt"
	"time"
)

func main() {
    
    
	// 首先我们来看看基本的速率限制.
	// 假设我们想要处理对传入请求的限制.
	// 我们将通过同名的通道来处理这些请求.
	requets := make(chan int, 5)
	for i := 1; i <= 5; i++ {
    
    
		requets <- i
	}
	close(requets)

	// 此limiter通道将每200毫秒接受一个值,这是我们速率限制方案中的调节器
	limiter := time.Tick(200 * time.Millisecond)

	// 通过在服务每个请求之前阻塞在limiter通道上, 我们将自己限制在每200毫秒处理一个请求.
	for req := range requets {
    
    
		<-limiter
		fmt.Println("request", req, time.Now())
	}
	// 我们可能希望在速率限制方案中允许短的突发请求, 同时保留整体的速率限制.
	// 我们可以通过带缓冲的limiter通道来实现这一点.
	// 这个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毫秒处理一次.
对于第二批请求, 由于突发速率的限制,我们立即服务了前3个请求, 然后服务其余2个请求, 每个请求延迟约200ms.

$ 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

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

下一节将介绍: 原子计数器.

猜你喜欢

转载自blog.csdn.net/weixin_43547795/article/details/130872902
今日推荐