令牌桶算法常常用于实现限速器,并能够允许突发数据的发送。
这里尝试用Golang实现一下令牌桶算法。
第一个版本参考
package main
import (
"fmt"
"time"
)
func logs(args ...interface{}) {
fmt.Println(args...)
}
func tokenBucket(limit int, rate int) chan struct{} {
tb := make(chan struct{}, limit)
ticker := time.NewTicker(time.Duration(1) * time.Second)
for i := 0; i < limit; i++ {
tb <- struct{}{}
}
go func() {
for {
for i := 0; i < rate; i++ {
tb <- struct{}{}
}
<-ticker.C
}
}()
return tb
}
func popToken(bucket chan struct{}, n int) {
for i := 0; i < n; i++ {
<-bucket
}
}
func testTokenBucket() {
rate := 10
tb := tokenBucket(20, rate)
dataLen := 100
for i := 0; i <= dataLen; i += rate {
popToken(tb, rate)
logs(i)
}
}
func main() {
testTokenBucket()
}
第二个版本参考
type TokenBucket struct {
rate int
limit int
currentAmount int
lastConsumeTime int64
}
func currentTime() int64 {
return time.Now().Unix()
}
func (tb *TokenBucket) popToken(n int) {
ticker := time.NewTicker(500 * time.Millisecond)
for n > tb.currentAmount {
pre := tb.currentAmount + int(currentTime()-tb.lastConsumeTime)*tb.rate
if pre > tb.limit {
tb.currentAmount = tb.limit
} else {
tb.currentAmount = pre
}
<-ticker.C
}
tb.lastConsumeTime = currentTime()
tb.currentAmount -= n
}
func newTokenBucket(limit int, rate int) *TokenBucket {
tb := TokenBucket{
rate: rate,
limit: limit,
currentAmount: 0,
lastConsumeTime: currentTime(),
}
return &tb
}