Source File
rate.go
Belonging Package
golang.org/x/time/rate
// Copyright 2015 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.// Package rate provides a rate limiter.package rateimport ()// Limit defines the maximum frequency of some events.// Limit is represented as number of events per second.// A zero Limit allows no events.type Limit float64// Inf is the infinite rate limit; it allows all events (even if burst is zero).const Inf = Limit(math.MaxFloat64)// Every converts a minimum time interval between events to a Limit.func ( time.Duration) Limit {if <= 0 {return Inf}return 1 / Limit(.Seconds())}// A Limiter controls how frequently events are allowed to happen.// It implements a "token bucket" of size b, initially full and refilled// at rate r tokens per second.// Informally, in any large enough time interval, the Limiter limits the// rate to r tokens per second, with a maximum burst size of b events.// As a special case, if r == Inf (the infinite rate), b is ignored.// See https://en.wikipedia.org/wiki/Token_bucket for more about token buckets.//// The zero value is a valid Limiter, but it will reject all events.// Use NewLimiter to create non-zero Limiters.//// Limiter has three main methods, Allow, Reserve, and Wait.// Most callers should use Wait.//// Each of the three methods consumes a single token.// They differ in their behavior when no token is available.// If no token is available, Allow returns false.// If no token is available, Reserve returns a reservation for a future token// and the amount of time the caller must wait before using it.// If no token is available, Wait blocks until one can be obtained// or its associated context.Context is canceled.//// The methods AllowN, ReserveN, and WaitN consume n tokens.//// Limiter is safe for simultaneous use by multiple goroutines.type Limiter struct {mu sync.Mutexlimit Limitburst inttokens float64// last is the last time the limiter's tokens field was updatedlast time.Time// lastEvent is the latest time of a rate-limited event (past or future)lastEvent time.Time}// Limit returns the maximum overall event rate.func ( *Limiter) () Limit {.mu.Lock()defer .mu.Unlock()return .limit}// Burst returns the maximum burst size. Burst is the maximum number of tokens// that can be consumed in a single call to Allow, Reserve, or Wait, so higher// Burst values allow more events to happen at once.// A zero Burst allows no events, unless limit == Inf.func ( *Limiter) () int {.mu.Lock()defer .mu.Unlock()return .burst}// TokensAt returns the number of tokens available at time t.func ( *Limiter) ( time.Time) float64 {.mu.Lock():= .advance() // does not mutate lim.mu.Unlock()return}// Tokens returns the number of tokens available now.func ( *Limiter) () float64 {return .TokensAt(time.Now())}// NewLimiter returns a new Limiter that allows events up to rate r and permits// bursts of at most b tokens.func ( Limit, int) *Limiter {return &Limiter{limit: ,burst: ,tokens: float64(),}}// Allow reports whether an event may happen now.func ( *Limiter) () bool {return .AllowN(time.Now(), 1)}// AllowN reports whether n events may happen at time t.// Use this method if you intend to drop / skip events that exceed the rate limit.// Otherwise use Reserve or Wait.func ( *Limiter) ( time.Time, int) bool {return .reserveN(, , 0).ok}// A Reservation holds information about events that are permitted by a Limiter to happen after a delay.// A Reservation may be canceled, which may enable the Limiter to permit additional events.type Reservation struct {ok boollim *Limitertokens inttimeToAct time.Time// This is the Limit at reservation time, it can change later.limit Limit}// OK returns whether the limiter can provide the requested number of tokens// within the maximum wait time. If OK is false, Delay returns InfDuration, and// Cancel does nothing.func ( *Reservation) () bool {return .ok}// Delay is shorthand for DelayFrom(time.Now()).func ( *Reservation) () time.Duration {return .DelayFrom(time.Now())}// InfDuration is the duration returned by Delay when a Reservation is not OK.const InfDuration = time.Duration(math.MaxInt64)// DelayFrom returns the duration for which the reservation holder must wait// before taking the reserved action. Zero duration means act immediately.// InfDuration means the limiter cannot grant the tokens requested in this// Reservation within the maximum wait time.func ( *Reservation) ( time.Time) time.Duration {if !.ok {return InfDuration}:= .timeToAct.Sub()if < 0 {return 0}return}// Cancel is shorthand for CancelAt(time.Now()).func ( *Reservation) () {.CancelAt(time.Now())}// CancelAt indicates that the reservation holder will not perform the reserved action// and reverses the effects of this Reservation on the rate limit as much as possible,// considering that other reservations may have already been made.func ( *Reservation) ( time.Time) {if !.ok {return}.lim.mu.Lock()defer .lim.mu.Unlock()if .lim.limit == Inf || .tokens == 0 || .timeToAct.Before() {return}// calculate tokens to restore// The duration between lim.lastEvent and r.timeToAct tells us how many tokens were reserved// after r was obtained. These tokens should not be restored.:= float64(.tokens) - .limit.tokensFromDuration(.lim.lastEvent.Sub(.timeToAct))if <= 0 {return}// advance time to now:= .lim.advance()// calculate new number of tokens+=if := float64(.lim.burst); > {=}// update state.lim.last =.lim.tokens =if .timeToAct == .lim.lastEvent {:= .timeToAct.Add(.limit.durationFromTokens(float64(-.tokens)))if !.Before() {.lim.lastEvent =}}}// Reserve is shorthand for ReserveN(time.Now(), 1).func ( *Limiter) () *Reservation {return .ReserveN(time.Now(), 1)}// ReserveN returns a Reservation that indicates how long the caller must wait before n events happen.// The Limiter takes this Reservation into account when allowing future events.// The returned Reservation’s OK() method returns false if n exceeds the Limiter's burst size.// Usage example://// r := lim.ReserveN(time.Now(), 1)// if !r.OK() {// // Not allowed to act! Did you remember to set lim.burst to be > 0 ?// return// }// time.Sleep(r.Delay())// Act()//// Use this method if you wish to wait and slow down in accordance with the rate limit without dropping events.// If you need to respect a deadline or cancel the delay, use Wait instead.// To drop or skip events exceeding rate limit, use Allow instead.func ( *Limiter) ( time.Time, int) *Reservation {:= .reserveN(, , InfDuration)return &}// Wait is shorthand for WaitN(ctx, 1).func ( *Limiter) ( context.Context) ( error) {return .WaitN(, 1)}// WaitN blocks until lim permits n events to happen.// It returns an error if n exceeds the Limiter's burst size, the Context is// canceled, or the expected wait time exceeds the Context's Deadline.// The burst limit is ignored if the rate limit is Inf.func ( *Limiter) ( context.Context, int) ( error) {// The test code calls lim.wait with a fake timer generator.// This is the real timer generator.:= func( time.Duration) (<-chan time.Time, func() bool, func()) {:= time.NewTimer()return .C, .Stop, func() {}}return .wait(, , time.Now(), )}// wait is the internal implementation of WaitN.func ( *Limiter) ( context.Context, int, time.Time, func( time.Duration) (<-chan time.Time, func() bool, func())) error {.mu.Lock():= .burst:= .limit.mu.Unlock()if > && != Inf {return fmt.Errorf("rate: Wait(n=%d) exceeds limiter's burst %d", , )}// Check if ctx is already cancelledselect {case <-.Done():return .Err()default:}// Determine wait limit:= InfDurationif , := .Deadline(); {= .Sub()}// Reserve:= .reserveN(, , )if !.ok {return fmt.Errorf("rate: Wait(n=%d) would exceed context deadline", )}// Wait if necessary:= .DelayFrom()if == 0 {return nil}, , := ()defer ()() // only has an effect when testingselect {case <-:// We can proceed.return nilcase <-.Done():// Context was canceled before we could proceed. Cancel the// reservation, which may permit other events to proceed sooner..Cancel()return .Err()}}// SetLimit is shorthand for SetLimitAt(time.Now(), newLimit).func ( *Limiter) ( Limit) {.SetLimitAt(time.Now(), )}// SetLimitAt sets a new Limit for the limiter. The new Limit, and Burst, may be violated// or underutilized by those which reserved (using Reserve or Wait) but did not yet act// before SetLimitAt was called.func ( *Limiter) ( time.Time, Limit) {.mu.Lock()defer .mu.Unlock():= .advance().last =.tokens =.limit =}// SetBurst is shorthand for SetBurstAt(time.Now(), newBurst).func ( *Limiter) ( int) {.SetBurstAt(time.Now(), )}// SetBurstAt sets a new burst size for the limiter.func ( *Limiter) ( time.Time, int) {.mu.Lock()defer .mu.Unlock():= .advance().last =.tokens =.burst =}// reserveN is a helper method for AllowN, ReserveN, and WaitN.// maxFutureReserve specifies the maximum reservation wait duration allowed.// reserveN returns Reservation, not *Reservation, to avoid allocation in AllowN and WaitN.func ( *Limiter) ( time.Time, int, time.Duration) Reservation {.mu.Lock()defer .mu.Unlock()if .limit == Inf {return Reservation{ok: true,lim: ,tokens: ,timeToAct: ,}}:= .advance()// Calculate the remaining number of tokens resulting from the request.-= float64()// Calculate the wait durationvar time.Durationif < 0 {= .limit.durationFromTokens(-)}// Decide result:= <= .burst && <=// Prepare reservation:= Reservation{ok: ,lim: ,limit: .limit,}if {.tokens =.timeToAct = .Add()// Update state.last =.tokens =.lastEvent = .timeToAct}return}// advance calculates and returns an updated number of tokens for lim// resulting from the passage of time.// lim is not changed.// advance requires that lim.mu is held.func ( *Limiter) ( time.Time) ( float64) {:= .lastif .Before() {=}// Calculate the new number of tokens, due to time that passed.:= .Sub():= .limit.tokensFromDuration():= .tokens +if := float64(.burst); > {=}return}// durationFromTokens is a unit conversion function from the number of tokens to the duration// of time it takes to accumulate them at a rate of limit tokens per second.func ( Limit) ( float64) time.Duration {if <= 0 {return InfDuration}:= ( / float64()) * float64(time.Second)// Cap the duration to the maximum representable int64 value, to avoid overflow.if > float64(math.MaxInt64) {return InfDuration}return time.Duration()}// tokensFromDuration is a unit conversion function from a time duration to the number of tokens// which could be accumulated during that duration at a rate of limit tokens per second.func ( Limit) ( time.Duration) float64 {if <= 0 {return 0}return .Seconds() * float64()}
![]() |
The pages are generated with Golds v0.8.2. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds. |