Ограничиваем скорость операций в Golang | OTUS

Ограничиваем скорость операций в Golang

Для ограничения скорости операций в единицу времени в языке программирования Go можно использовать time.Ticker. Это неплохо работает для скоростей до нескольких десятков операций в секунду. Если же речь идет о более высоких скоростях, тогда лучше отдавать предпочтение ограничителю скорости сегмента токенов, например, Limiter из golang.org/x/time/rate.

import "time"

const rateLimit = time.Second / 10  // 10 calls per second

// Client это интерфейс, 
// который вызывает что-то с полезной нагрузкой.
type Client interface {
  Call(*Payload)
}

// Payload это некоторая полезная нагрузка, 
// которую Client отправляет при вызове.
type Payload struct {}

// RateLimitCall ограничивает скорость клиентских вызовов полезной нагрузки.
func RateLimitCall(client Client, payloads []*Payload) {
  throttle := time.Tick(rateLimit)

  for _, payload := range payloads {
    <-throttle  // ограничение скорости клиентских вызовов
    go client.Call(payload)
  }
}

Если же надо разрешить некоторые всплески, достаточно добавить буфер к дросселю:

import "time"

const rateLimit = time.Second / 10  // 10 calls per second

// Client это интерфейс, 
// который вызывает что-то с полезной нагрузкой.
type Client interface {
  Call(*Payload)
}

// Payload это некоторая полезная нагрузка, 
// которую Client отправляет при вызове.
type Payload struct {}

// BurstRateLimitCall позволяет ограничивать 
// пакетную скорость клиентских вызовов полезной нагрузки.
func BurstRateLimitCall(ctx context.Context, client Client, payloads []*Payload, burstLimit int) {
  throttle := make(chan time.Time, burstLimit)

  ctx, cancel := context.WithCancel(ctx)
  defer cancel()

  go func() {
    ticker := time.NewTicker(rateLimit)
    defer ticker.Stop()
    for t := range ticker.C {
        select {
        case throttle <- t:
        case <-ctx.Done():
            return // выходим из горутины, когда окружающая функция завершается
        }
    }
  }()

  for _, payload := range payloads {
    <-throttle  // ограничение скорости клиентских вызовов
    go client.Call(payload)
  }
}

По материалам блога https://golang-blog.blogspot.com/.

Не пропустите новые полезные статьи!

Спасибо за подписку!

Мы отправили вам письмо для подтверждения вашего email.
С уважением, OTUS!

Автор
0 комментариев
Для комментирования необходимо авторизоваться