Sobes.tech
Middle+

// Quando si aggiorna un ordine, dobbiamo inviare i dati dell'ordine a diversi servizi (API di terze parti) // il numero di servizi sta crescendo (potenzialmente migliaia+) // abbiamo scritto il codice, all'inizio tutto andava bene, ma col tempo il nostro servizio ha iniziato a consumare molta memoria func (s *orderService) SendOrder(ctx context.Context, hosts []string, order Order) { for i := 0; i < len(hosts); i++ { go func() { // Immaginiamo che sia una lunga chiamata di rete response, err := s.httpClient.Send(ctx, hosts[i], order) if err != nil { s.logger.Error(ctx, "fallimento nell'invio", err) return } s.logger.Info(ctx, "successo", response) }() } }

sobes.tech AI

Risposta dell'AI

В представленном коде есть проблема с использованием переменной цикла внутри горутины — переменная hosts[i] может измениться к моменту выполнения горутины, что приведёт к неправильным вызовам.

Кроме того, при большом количестве сервисов (тысячи и более) запуск тысяч горутин одновременно приведёт к высокому потреблению памяти и ресурсов.

Рекомендации по исправлению:

  1. Передавать переменную в замыкание, чтобы избежать захвата изменяющейся переменной:
for i := 0; i < len(hosts); i++ {
    host := hosts[i]
    go func() {
        response, err := s.httpClient.Send(ctx, host, order)
        if err != nil {
            s.logger.Error(ctx, "failed to send", err)
            return
        }
        s.logger.Info(ctx, "success", response)
    }()
}
  1. Ограничить количество одновременно работающих горутин с помощью семафора или worker pool, чтобы не создавать тысячи горутин одновременно:
sem := make(chan struct{}, 100) // ограничение до 100 параллельных вызовов
for _, host := range hosts {
    sem <- struct{}{}
    go func(h string) {
        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)
}
// дождаться завершения всех горутин
for i := 0; i < cap(sem); i++ {
    sem <- struct{}{}
}

Таким образом, мы избегаем утечек памяти и контролируем нагрузку на систему.