programowanieProgramista Go

Co trzeba wiedzieć o pracy z time.Timer i time.Ticker w Go? Jakie są kluczowe różnice, cechy poprawnego użycia i powszechne błędy przy ich stop/reset?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź

Pakiet time oferuje dwa przydatne narzędzia: Timer i Ticker.

  • Timer służy do jednorazowego opóźnienia (uruchamia się raz po określonym czasie).
  • Ticker — do regularnych wydarzeń okresowych (interwał).

Kluczowe różnice:

  • Timer po wyzwoleniu "wygasa", należy go zresetować (Reset), żeby użyć ponownie.
  • Ticker generuje wydarzenia, dopóki nie zostanie jawnie zatrzymany metodą Stop().

Cechy użycia:

  • Zawsze wywołuj Stop() dla Timer/Ticker po zakończeniu pracy, aby uniknąć wycieków zasobów.
  • Po wywołaniu Stop() dla Timer, może być konieczne „osuszenie” kanału: jeśli timer wyzwolił się przed Stop(), odczyt z kanału jest obowiązkowy.

Przykład poprawnego użycia Timer:

t := time.NewTimer(2 * time.Second) defer t.Stop() // obowiązkowe! select { case <-t.C: fmt.Println("Czas minął!") case <-otherDone: if !t.Stop() { <-t.C // osuszamy kanał, jeśli to konieczne } }

Pytanie z podstępem

Czy można od razu ponownie używać Timer po otrzymaniu wartości z kanału t.C? Co się stanie, jeśli nie zrobimy t.Stop()?

Odpowiedź: Timer nie powinien być natychmiast resetowany bez wywołania Stop() i ewentualnego odczytu z kanału. Jeśli nie zrobisz t.Stop(), może pozostać "martwy" gorutyna lub niespodziewany wyzwalacz w następnym cyklu (kanał nie został oczyszczony). Poprawne użycie: wywołaj Stop(), a jeśli Stop() zwrócił false — koniecznie osusz kanał odczytem z t.C.

Przykłady rzeczywistych błędów z powodu braku znajomości szczegółów tematu


Historia

W serwisie powiadomień startupu używano timerów do zresetowania prób dostawy. Po wyzwoleniu natychmiast je resetowano bez zatrzymywania — w rezultacie liczba gorutyn rosła, proces "wyciekał", system zawieszał się z powodu braku pamięci.

Historia

W dużym projekcie e-commerce do okresowych aktualizacji produktów stosowano Ticker, który nie był zatrzymywany po zakończeniu hendlara. Handler "wisiał" nawet po usunięciu użytkownika, zużywając CPU.

Historia

W testach nie wywoływano Stop() dla timera — testy zawieszały się losowo, ponieważ kanał timera nie był zwalniany, oczekiwano na drugi "ping" od timera, który nigdy nie nadchodził.