понедельник, 28 июня 2021 г.

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

Чтобы ограничить скорость операций в единицу времени, используйте 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)
  }
}


Читайте также: