golang頻率限制 golang.org/x/time/rate 使用說明

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

官方連結

介面介紹

type Limiter

type Limiter struct {    // contains filtered or unexported fields}

Limter限制時間的發生頻率,採用令牌池的演算法實現。這個池子一開始容量為b,裝滿b個令牌,然後每秒往裡面填充r個令牌。
由於令牌池中最多有b個令牌,所以一次最多隻能允許b個事件發生,一個事件花費掉一個令牌。

Limter提供三中主要的函數 Allow, Reserve, and Wait. 大部分時候使用Wait。

func NewLimiter

func NewLimiter(r Limit, b int) *Limiter

NewLimiter 返回一個新的Limiter。

func (*Limiter) [Allow]

func (lim *Limiter) Allow() bool

Allow 是函數 AllowN(time.Now(), 1)的簡化函數。

func (*Limiter) AllowN

func (lim *Limiter) AllowN(now time.Time, n int) bool

AllowN標識在時間now的時候,n個事件是否可以同時發生(也意思就是now的時候是否可以從令牌池中取n個令牌)。如果你需要在事件超出頻率的時候丟棄或跳過事件,就使用AllowN,否則使用Reserve或Wait.

func (*Limiter) Reserve

func (lim *Limiter) Reserve() *Reservation

Reserve是ReserveN(time.Now(), 1).的簡化形式。

func (*Limiter) ReserveN

func (lim *Limiter) ReserveN(now time.Time, n int) *Reservation

ReserveN 返回對象Reservation ,標識調用者需要等多久才能等到n個事件發生(意思就是等多久令牌池中至少含有n個令牌)。

如果ReserveN 傳入的n大於令牌池的容量b,那麼返回false.
使用範例如下:

r := lim.ReserveN(time.Now(), 1)if !r.OK() {  // Not allowed to act! Did you remember to set lim.burst to be > 0 ?我只要1個事件發生仍然返回false,是不是b設定為了0?  return}time.Sleep(r.Delay())Act()

如果希望根據頻率限制等待和降低事件發生的速度而不丟掉事件,就使用這個方法。
我認為這裡要表達的意思就是如果事件發生的頻率是可以由調用者控制的話,可以用ReserveN 來控制事件發生的速度而不丟掉事件。如果要使用context的到期日或cancel方法的話,使用WaitN。

func (*Limiter) Wait

func (lim *Limiter) Wait(ctx context.Context) (err error)

Wait是WaitN(ctx, 1)的簡化形式。

func (*Limiter) WaitN

func (lim *Limiter) WaitN(ctx context.Context, n int) (err error)

WaitN 阻塞當前直到lim允許n個事件的發生。

  • 如果n超過了令牌池的容量大小則報錯。
  • 如果Context被取消了則報錯。
  • 如果lim的等待時間超過了Context的逾時時間則報錯。

測試 AllowN

package mainimport (    "os"    "time"    "golang.org/x/time/rate"    "github.com/op/go-logging")var log = logging.MustGetLogger("example")// Example format string. Everything except the message has a custom color// which is dependent on the log level. Many fields have a custom output// formatting too, eg. the time returns the hour down to the milli second.var format = logging.MustStringFormatter(    `%{color}%{time:15:04:05.000} %{shortfunc}  %{level:.4s} %{id:03x}%{color:reset} %{message}`,)func main() {    backend1 := logging.NewLogBackend(os.Stderr, "", 0)    backend2 := logging.NewLogBackend(os.Stderr, "", 0)    backend2Formatter := logging.NewBackendFormatter(backend2, format)    backend1Leveled := logging.AddModuleLevel(backend1)    backend1Leveled.SetLevel(logging.ERROR, "")    logging.SetBackend(backend1Leveled, backend2Formatter)    r := rate.Every(1)    limit := rate.NewLimiter(r, 10)    for {        if limit.AllowN(time.Now(), 8) {            log.Info("log:event happen")        } else {            log.Info("log:event not allow")        }    }}

測試ReserveN

參考YY哥

package mainimport (    "bytes"    "fmt"    "io"    "time"    "golang.org/x/time/rate")type reader struct {    r      io.Reader    limiter *rate.Limiter}// Reader returns a reader that is rate limited by// the given token bucket. Each token in the bucket// represents one byte.func NewReader(r io.Reader, l *rate.Limiter) io.Reader {    return &reader{        r:      r,        limiter:l,    }}func (r *reader) Read(buf []byte) (int, error) {    n, err := r.r.Read(buf)    if n <= 0 {        return n, err    }    now := time.Now()    rv := r.limiter.ReserveN(now, n)    if !rv.OK() {        return 0, fmt.Errorf("Exceeds limiter's burst")    }    delay := rv.DelayFrom(now)    //fmt.Printf("Read %d bytes, delay %d\n", n, delay)    time.Sleep(delay)    return n, err}func main() {    // Source holding 1MB    src := bytes.NewReader(make([]byte, 1024*1024))    // Destination    dst := &bytes.Buffer{}    // Bucket adding 100KB every second, holding max 100KB    limit := rate.NewLimiter(100*1024, 100*1024)    start := time.Now()    buf := make([]byte, 10*1024)    // Copy source to destination, but wrap our reader with rate limited one    //io.CopyBuffer(dst, NewReader(src, limit), buf)    r := NewReader(src, limit)    for{        if n, err := r.Read(buf); err == nil {            dst.Write(buf[0:n])        }else{            break        }    }    fmt.Printf("Copied %d bytes in %s\n", dst.Len(), time.Since(start))}

後記

之前一直在CSDN上寫文章,後面會逐步轉換到簡書上,還請大家多多支援。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.