github.com/tickstep/library-go@v0.1.1/requester/rio/speeds/ratelimit.go (about) 1 package speeds 2 3 import ( 4 "sync" 5 "sync/atomic" 6 "time" 7 ) 8 9 type ( 10 RateLimit struct { 11 MaxRate int64 12 13 starTimestamp int64 14 count int64 15 interval time.Duration 16 ticker *time.Ticker 17 muChan chan struct{} 18 closeChan chan struct{} 19 backServiceOnce sync.Once 20 } 21 22 // AddCountFunc func() (count int64) 23 ) 24 25 func NewRateLimit(maxRate int64) *RateLimit { 26 return &RateLimit{ 27 MaxRate: maxRate, 28 } 29 } 30 31 func (rl *RateLimit) SetInterval(i time.Duration) { 32 if i <= 0 { 33 i = 1 * time.Second 34 } 35 rl.interval = i 36 if rl.ticker != nil { 37 rl.ticker.Stop() 38 rl.ticker = time.NewTicker(i) 39 } 40 } 41 42 func (rl *RateLimit) Stop() { 43 if rl.ticker != nil { 44 rl.ticker.Stop() 45 } 46 if rl.closeChan != nil { 47 close(rl.closeChan) 48 } 49 return 50 } 51 52 func (rl *RateLimit) resetChan() { 53 if rl.muChan != nil { 54 close(rl.muChan) 55 } 56 rl.muChan = make(chan struct{}) 57 } 58 59 func (rl *RateLimit) backService() { 60 if rl.interval <= 0 { 61 rl.interval = 200 * time.Millisecond 62 } 63 rl.ticker = time.NewTicker(rl.interval) 64 rl.closeChan = make(chan struct{}) 65 rl.resetChan() 66 rl.starTimestamp = time.Now().UnixNano() 67 go func() { 68 for { 69 select { 70 case <-rl.ticker.C: 71 if rl.rate() <= rl.MaxRate { 72 rl.resetChan() 73 } 74 case <-rl.closeChan: 75 return 76 } 77 } 78 }() 79 } 80 81 func (rl *RateLimit) Add(count int64) { 82 rl.backServiceOnce.Do(rl.backService) 83 for { 84 if rl.rate() >= rl.MaxRate { // 超出最大限额 85 // 阻塞 86 <-rl.muChan 87 continue 88 } 89 atomic.AddInt64(&rl.count, count) 90 if atomic.LoadInt64(&rl.count) < 0 { 91 // reach the max value 92 atomic.StoreInt64(&rl.count, 0) 93 rl.starTimestamp = time.Now().Unix() 94 } 95 break 96 } 97 } 98 99 func (rl *RateLimit) rate() int64 { 100 timeElapseSecond := (time.Now().UnixNano() - rl.starTimestamp) / 1e9 101 if timeElapseSecond <= 0 { 102 timeElapseSecond = 1 103 } 104 return atomic.LoadInt64(&rl.count) / (timeElapseSecond) 105 }