ПрограммированиеGo разработчик

Что нужно знать о работе с time.Timer и time.Ticker в Go? Каковы ключевые отличия, особенности корректного использования и распространённые ошибки при их stop/reset?

Проходите собеседования с ИИ помощником Hintsage

Ответ

Пакет time предоставляет два полезных инструмента: Timer и Ticker.

  • Timer используется для однократной задержки (один раз срабатывает через заданное время).
  • Ticker — для регулярных периодических событий (интервал).

Ключевые отличия:

  • Timer после срабатывания "потухает", его нужно сбросить (Reset), чтобы использовать ещё раз.
  • Ticker генерирует события до тех пор, пока явно не остановлен методом Stop().

Особенности использования:

  • Всегда вызывайте Stop() у Timer/Ticker при завершении работы, чтобы не возникало утечек ресурсов.
  • После вызова Stop() у Timer, возможно требуется «осушить» канал: если таймер сработал до Stop(), чтение из канала обязательно.

Пример корректного использования Timer:

t := time.NewTimer(2 * time.Second) defer t.Stop() // обязательно! select { case <-t.C: fmt.Println("Time's up!") case <-otherDone: if !t.Stop() { <-t.C // осушаем канал, если нужно } }

Вопрос с подвохом

Можно ли сразу повторно использовать Timer после получения значения из канала t.C? Что произойдет, если не сделать t.Stop()?

Ответ: Таймер не должен немедленно сбрасываться без вызова Stop() и возможного чтения из канала. Если не сделать t.Stop(), может остаться "мертвая" горутина или неожиданный триггер на следующем цикле (канал не очищен). Правильное использование: вызовите Stop(), а если Stop() вернул false — обязательно осушите канал чтением из t.C.

Примеры реальных ошибок из-за незнания тонкостей темы


История

В сервисе нотификаций стартапа для сброса попыток доставки использовались таймеры. После срабатывания их сразу сбрасывали без остановки — итог: поток горутин рос, процесс "утекал", система ложилась из-за нехватки памяти.

История

В крупном e-commerce проекте для периодических обновлений товара использовался Ticker, который не останавливали при завершении хендлера. Обработчик "висел" даже после удаления пользователя, продолжается тратить CPU.

История

В тестах не вызывали Stop() для таймера — тесты висли рандомно из-за того, что канал таймера не освобождался, ожидался второй "пинг" от таймера, который никогда не приходил.