Sobes.tech
Principal

// Sipariş güncellenirken, sipariş verilerini birkaç hizmete (üçüncü taraflar) göndermemiz gerekiyor // hizmet sayısı artıyor (binlerce+ olabilir) // kodu yazdık, başlangıçta her şey iyi gidiyordu, ancak zamanla hizmetimiz çok fazla kaynak tüketmeye başladı // Bu kodu, çok sayıda hizmetle verimli çalışacak şekilde optimize etmemiz gerekiyor func (s *orderService) SendOrder(ctx context.Context, hosts []string, order Order) { for i := 0; i < len(hosts); i++ { go func() { // Bu uzun bir ağ çağrısı olduğunu hayal edin response, err := s.httpClient.Send(ctx, hosts[i], order) if err != nil { s.logger.Error(ctx, "gönderme başarısız", err) return } s.logger.Info(ctx, "başarılı", response) }() } }

sobes.tech yapay zeka

AI'dan gelen yanıt

В представленном коде есть несколько проблем, которые приводят к высокому потреблению ресурсов при большом количестве сервисов:

  1. Потенциальная утечка переменной цикла: в анонимной функции используется hosts[i], но i может измениться к моменту выполнения горутины. Нужно передавать hosts[i] как параметр функции.

  2. Запуск слишком большого количества горутин одновременно: если hosts содержит тысячи элементов, будет создано столько же горутин, что приведёт к высокому потреблению памяти и CPU.

  3. Отсутствие контроля параллелизма и ожидания завершения.

Как оптимизировать:

  • Использовать пул горутин с ограничением по количеству одновременно выполняемых задач (например, через семафор или канал).
  • Передавать значение host в горутину явно, чтобы избежать захвата переменной цикла.
  • Добавить механизм ожидания завершения всех отправок (например, sync.WaitGroup).

Пример оптимизированного кода:

func (s *orderService) SendOrder(ctx context.Context, hosts []string, order Order) {
    const maxConcurrency = 100 // ограничение по числу параллельных запросов
    sem := make(chan struct{}, maxConcurrency)
    var wg sync.WaitGroup

    for _, host := range hosts {
        wg.Add(1)
        sem <- struct{}{} // захватываем слот

        go func(h string) {
            defer wg.Done()
            defer func() { <-sem }() // освобождаем слот

            response, err := s.httpClient.Send(ctx, h, order)
            if err != nil {
                s.logger.Error(ctx, "failed to send", err)
                return
            }
            s.logger.Info(ctx, "success", response)
        }(host)
    }

    wg.Wait() // ждем завершения всех горутин
}

Такой подход позволяет контролировать нагрузку на систему, не создавая слишком много горутин одновременно, и предотвращает утечку переменной цикла.