Как ограничить отправку запросов из горутин?

В Go есть несколько способов ограничить отправку запросов из горутин для предотвращения перегрузки системы или превышения ограничений сторонних сервисов. Рассмотрим некоторые из них.

1. Использование буферизованных каналов: Вы можете создать канал с ограниченной емкостью и использовать его для передачи запросов. Если канал заполнен, отправка новых запросов будет блокироваться до тех пор, пока не освободится место в канале. Например:

requests := make(chan Request, 10)
responses := make(chan Response)

// создаем горутину-обработчик
go func() {
   for req := range requests {
      // выполняем запрос и отправляем результат в канал responses
      resp := makeRequest(req)
      responses <- resp
   }
}()

// отправляем запросы в канал requests
for _, req := range allRequests {
   requests <- req
}

// получаем результаты из канала responses
for i := 0; i < len(allRequests); i++ {
   resp := <-responses
   // обрабатываем результат
}

2. Использование пула горутин: Вы можете создать ограниченное количество горутин в пуле и использовать его для обработки запросов. Когда все горутины заняты, новые запросы будут вставлены в очередь и ожидать своей очереди. Например:

const maxWorkers = 10

type WorkerPool struct {
   workers chan struct{}
}

func NewWorkerPool() *WorkerPool {
   return &WorkerPool{
      workers: make(chan struct{}, maxWorkers),
   }
}

func (p *WorkerPool) Submit(f func()) {
   p.workers <- struct{}{}
   go func() {
      f()
      <-p.workers
   }()
}

pool := NewWorkerPool()

for _, req := range allRequests {
   pool.Submit(func() {
      // обрабатываем запрос
      resp := makeRequest(req)

      // обрабатываем результат
   })
}

3. Использование семафоров: Вы можете использовать семафоры для управления количеством одновременно выполняемых горутин. Семафор — это счетчик, который контролирует количество разрешений для выполнения. Например:

const maxConcurrency = 5

var sem = make(chan struct{}, maxConcurrency)

for _, req := range allRequests {
   sem <- struct{}{}
   go func(r Request) {
      // обрабатываем запрос
      resp := makeRequest(r)

      // обрабатываем результат

      <-sem
   }(req)
}

Это только несколько примеров, как можно ограничить отправку запросов из горутин. В зависимости от конкретной ситуации и требований, вы можете использовать один из этих подходов или их комбинацию для эффективного управления параллельной обработкой запросов в вашей программе на Go.