因为平常使用某度的网盘,如果不办超级会员的话,下载速度会被限制的很低。然后我就在思考这个限速的功能是怎样实现的,可能以后自己会用上。查询资料后,发现令牌桶算法应该能很简单的实现需求,而且使用 golang 的 channel 很容易就能实现令牌桶算法。
令牌桶算法#
令牌桶算法的原理是系统会以一个恒定的速度往桶里放入令牌。如果有请求需要被处理,则需要先从桶里获取一个令牌,当桶里没有令牌可取时,则等待桶里有新的令牌或者拒绝服务。
golang 实现#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
| package main
import (
"log"
"time"
)
// 令牌桶
type RateLimit chan struct{}
// 获得令牌桶
func NewRateLimit(limit int, rate time.Duration) RateLimit {
r := make(RateLimit, limit)
ticker := time.NewTicker(rate)
// 按照传入速率往桶里放入令牌
go func() {
for {
for i := 0; i < limit; i++ {
select {
case r <- struct{}{}:
default:
}
}
<-ticker.C
}
}()
return r
}
// 获取令牌
func (r RateLimit) Limit(n int) {
for i := 0; i < n; i++ {
<-r
}
}
func main() {
start := time.Now()
// 获得限速器 限制条件为 100/s
rateLimit := NewRateLimit(100, time.Second)
// 模拟 500 个写入
for i := 0; i < 500; i++ {
rateLimit.Limit(1)
log.Println("this is", i)
}
log.Println("use time", time.Now().Sub(start))
}
|