go 令牌桶簡易實現(xiàn)

參考百度百科

令牌桶算法的基本過程如下:

  • 假如用戶配置的平均發(fā)送速率為r,則每隔1/r秒一個令牌被加入到桶中;
  • 假設桶最多可以存發(fā)b個令牌。如果令牌到達時令牌桶已經(jīng)滿了,那么這個令牌會被丟棄;
  • 當一個n個字節(jié)的數(shù)據(jù)包到達時,就從令牌桶中刪除n個令牌,并且數(shù)據(jù)包被發(fā)送到網(wǎng)絡;
package main

import (
    "fmt"
    "sync"
    "time"
)

type Bucket struct {
    cap   int //容量
    ch    chan bool   
    timer *time.Ticker //定時填充token
    mu    sync.Mutex
}

func NewBucket(cap int, interval time.Duration) *Bucket {
    bucket := &Bucket{
        cap:   cap,
        ch:    make(chan bool, cap),
        timer: time.NewTicker(interval),
    }
    go bucket.startTicker()
    return bucket
}

func (bucket *Bucket) startTicker() {
    for i := 0; i < bucket.cap; i++ {
        bucket.ch <- true
    }
    for {
        select {
        case <-bucket.timer.C:
            for i := len(bucket.ch); i < bucket.cap; i++ {
                bucket.Add()
            }
        }
    }
}

func (bucket *Bucket) Add() {
    bucket.mu.Lock()
    defer bucket.mu.Unlock()
    if len(bucket.ch) < bucket.cap {
        bucket.ch <- true
    }
}

func (bucket *Bucket) Get() bool {
    select {
    case <-bucket.ch:
        return true
    default:
        return false
    }
}

func main() {

    bucket := NewBucket(5, time.Second)
    for i := 0; i < 1000; i++ {
        time.Sleep(time.Millisecond * 100)
        go DoFunc(bucket, i)
    }
    for {
    }
}

func DoFunc(bucket *Bucket, index int) {
    if bucket.Get() {
        fmt.Printf("######### success : %d \n", index)
        bucket.Add() // 每次請求成功后執(zhí)行Add是否合理???每一時刻最多可有cap個token可用
    } else {
        fmt.Printf("######### failed : %d \n", index)
    }
}

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容