Historia pytania:
Wyciek goroutine to sytuacja, gdy goroutine nadal istnieje i wisi w pamięci, mimo że w rzeczywistości "straciła sens" (obliczenia się zakończyły, dane są niepotrzebne, ale nie ma warunku wyjścia). Podobnie jak w przypadku wycieków pamięci, ale dla wątków wykonawczych. Jest to krytyczne dla Go — duże obciążenie może prowadzić do wyczerpania zasobów.
Problem:
W przeciwieństwie do innych języków, gdzie bezpośrednie zarządzanie wątkami często prowadzi do ich ręcznego zamykania, w Go goroutines uruchamia się łatwo, ale nie zawsze kończą się poprawnie. Częsty błąd: główna logika się zakończyła, a goroutine "zamroziła się" — czeka na dane na zamkniętym kanale lub w ogóle nie doczeka się sygnału.
Rozwiązanie:
Aby zapobiec wyciekom, używa się konstrukcji kontrolnych: context, zamykanie kanałów, zmienne sygnalizacyjne. Ważne jest, aby z góry projektować ścieżki wyjścia z każdej goroutine, używać defer do oczyszczania. Przykład:
func worker(ctx context.Context, jobs <-chan int, results chan<- int) { for { select { case <-ctx.Done(): return case job, ok := <-jobs: if !ok { return } results <- job * 2 } } }
Kluczowe cechy:
Czy można po prostu zamknąć kanał, aby zatrzymać Goroutine?
Nie zawsze. Jeśli w select są inne case lub nie ma sprawdzenia zamknięcia przez ok, goroutine może pozostać "zawieszona".
val, ok := <-ch if !ok { return } // Tak jest poprawniej
Co się stanie, jeśli zapomnisz obsłużyć context.Done w select?
Goroutine nigdy się nie dowie, że nastąpiła anulacja — pozostanie "wieczna". To prosta droga do wycieku.
Czy można wychwycić wyciek za pomocą go runtime?
Nie ma standardowego narzędzia do śledzenia wycieków. Należy monitorować liczbę aktywnych goroutines przez runtime.NumGoroutine lub używać detektora wycieków zewnętrznych bibliotek.
W systemie wysyłki push uruchamiają goroutine na każdą przychodzącą wiadomość, ale zapominają je zatrzymać przy anulacji kontekstu lub zamknięciu kanału — setki "martwych" goroutines wisi w pamięci.
Zalety:
Wady:
Praca goroutine jest kontrolowana przez kontekst, na poziomie logiki biznesowej sprawdzane jest zakończenie z select, po udanym wysłaniu/opracowaniu kanał jest zamykany.
Zalety:
Wady: