美文网首页
2019-07-25

2019-07-25

作者: 肖四 | 来源:发表于2019-07-25 21:48 被阅读0次
    // The methods AllowN, ReserveN, and WaitN consume n tokens.
    type Limiter struct {
        limit Limit
        burst int
    
        mu     sync.Mutex
        tokens float64
        // last is the last time the limiter's tokens field was updated
        last 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 (lim *Limiter) Limit() Limit {
        lim.mu.Lock()
        defer lim.mu.Unlock()
        return lim.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 (lim *Limiter) Burst() int {
        return lim.burst
    }
    
    // NewLimiter returns a new Limiter that allows events up to rate r and permits
    // bursts of at most b tokens.
    func NewLimiter(r Limit, b int) *Limiter {
        return &Limiter{
            limit: r,
            burst: b,
        }
    }
    
    
    // Allow is shorthand for AllowN(time.Now(), 1).
    func (lim *Limiter) Allow() bool {
        return lim.AllowN(time.Now(), 1)
    }
    
    // AllowN reports whether n events may happen at time now.
    // Use this method if you intend to drop / skip events that exceed the rate limit.
    // Otherwise use Reserve or Wait.
    func (lim *Limiter) AllowN(now time.Time, n int) bool {
        return lim.reserveN(now, n, 0).ok
    }
    
    
    
    // Wait is shorthand for WaitN(ctx, 1).
    func (lim *Limiter) Wait(ctx context.Context) (err error) {
        return lim.WaitN(ctx, 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 (lim *Limiter) WaitN(ctx context.Context, n int) (err error) {
        if n > lim.burst && lim.limit != Inf {
            return fmt.Errorf("rate: Wait(n=%d) exceeds limiter's burst %d", n, lim.burst)
        }
        // Check if ctx is already cancelled
        select {
        case <-ctx.Done():
            return ctx.Err()
        default:
        }
        // Determine wait limit
        now := time.Now()
        waitLimit := InfDuration
        if deadline, ok := ctx.Deadline(); ok {
            waitLimit = deadline.Sub(now)
        }
        // Reserve
        r := lim.reserveN(now, n, waitLimit)
        if !r.ok {
            return fmt.Errorf("rate: Wait(n=%d) would exceed context deadline", n)
        }
        // Wait if necessary
        delay := r.DelayFrom(now)
        if delay == 0 {
            return nil
        }
        t := time.NewTimer(delay)
        defer t.Stop()
        select {
        case <-t.C:
            // We can proceed.
            return nil
        case <-ctx.Done():
            // Context was canceled before we could proceed.  Cancel the
            // reservation, which may permit other events to proceed sooner.
            r.Cancel()
            return ctx.Err()
        }
    }
    
    
    // Reserve is shorthand for ReserveN(time.Now(), 1).
    func (lim *Limiter) Reserve() *Reservation {
        return lim.ReserveN(time.Now(), 1)
    }
    
    // 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 (lim *Limiter) reserveN(now time.Time, n int, maxFutureReserve time.Duration) Reservation {
        lim.mu.Lock()
    
        if lim.limit == Inf {
            lim.mu.Unlock()
            return Reservation{
                ok:        true,
                lim:       lim,
                tokens:    n,
                timeToAct: now,
            }
        }
    
        now, last, tokens := lim.advance(now)
    
        // Calculate the remaining number of tokens resulting from the request.
        tokens -= float64(n)
    
        // Calculate the wait duration
        var waitDuration time.Duration
        if tokens < 0 {
            waitDuration = lim.limit.durationFromTokens(-tokens)
        }
    
        // Decide result
        ok := n <= lim.burst && waitDuration <= maxFutureReserve
    
        // Prepare reservation
        r := Reservation{
            ok:    ok,
            lim:   lim,
            limit: lim.limit,
        }
        if ok {
            r.tokens = n
            r.timeToAct = now.Add(waitDuration)
        }
    
        // Update state
        if ok {
            lim.last = now
            lim.tokens = tokens
            lim.lastEvent = r.timeToAct
        } else {
            lim.last = last
        }
    
        lim.mu.Unlock()
        return r
    }
    
    
    package main
     
    import (
        "context"
        "fmt"
        "time"
     
        "golang.org/x/time/rate"
    )
     
    func main() {
        l := rate.NewLimiter(2, 5)
        ctx := context.Background()
        start := time.Now()
        // 要处理二十个事件
        for i := 0; i < 20; i++ {
            l.Wait(ctx)
            // dosomething
        }
        fmt.Println(time.Since(start)) 
    }
    
    
    

    相关文章

      网友评论

          本文标题:2019-07-25

          本文链接:https://www.haomeiwen.com/subject/bnnkrctx.html