因为平常使用某度的网盘,如果不办超级会员的话,下载速度会被限制的很低。然后我就在思考这个限速的功能是怎样实现的,可能以后自己会用上。查询资料后,发现令牌桶算法应该能很简单的实现需求,而且使用 golang 的 channel 很容易就能实现令牌桶算法。

令牌桶算法

令牌桶算法的原理是系统会以一个恒定的速度往桶里放入令牌。如果有请求需要被处理,则需要先从桶里获取一个令牌,当桶里没有令牌可取时,则等待桶里有新的令牌或者拒绝服务。

pool

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