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 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
| package main
import ( "os" "sync" "time"
logger "github.com/sirupsen/logrus" "github.com/x-cray/logrus-prefixed-formatter" )
func init() { logger.SetFormatter(&prefixed.TextFormatter{ TimestampFormat: "2006-01-02 15:04:05", FullTimestamp: true, ForceFormatting: true, DisableColors: true, }) logger.SetOutput(os.Stdout) logger.SetLevel(logger.DebugLevel) }
type TokenBucket struct { mu sync.Mutex startTime time.Time availableTokens int64 capacity int64 fillInterval time.Duration lastTick int64 }
func NewTokenBucket(qps, capacity int64) *TokenBucket { return &TokenBucket{ startTime: time.Now(), availableTokens: capacity, capacity: capacity, lastTick: 0, fillInterval: time.Duration(int64(time.Second) / qps), } }
func (tb *TokenBucket) adjust() { if (tb.availableTokens) >= tb.capacity { return } now := time.Now() tick := int64(now.Sub(tb.startTime) / tb.fillInterval) tb.availableTokens += tick - tb.lastTick if tb.availableTokens > tb.capacity { tb.availableTokens = tb.capacity } tb.lastTick = tick }
func (tb *TokenBucket) TakeAvailable(count int64) int64 { tb.mu.Lock() defer tb.mu.Unlock()
tb.adjust()
if tb.availableTokens <= 0 { return 0 }
if count >= tb.availableTokens { count = tb.availableTokens }
tb.availableTokens -= count return count }
func task(qps, num int64, timeNeed time.Duration) { logger.Infof("task qps: %v, num: %v, timeNeed: %.3fs", qps, num, timeNeed.Seconds()) bucket := NewTokenBucket(qps, qps) startTime := time.Now() lastTime := startTime
for i := int64(1); i <= num; { if bucket.TakeAvailable(1) == 1 { time.Sleep(timeNeed) i++ if i%1000 == 0 { now := time.Now() logger.Infof("rate: %.3f", 1000/now.Sub(lastTime).Seconds()) lastTime = now } } }
logger.Infof("task over, used: %.3fs", time.Now().Sub(startTime).Seconds()) }
func main() { task(10000, 100000, 0) task(10000, 15000, 2*time.Millisecond) task(500, 10000, 0) }
|