time.Timer în Go

Un temporizator care trimite un singur semnal pe canalul C după o durată; poate fi oprit (Stop) sau repornit (Reset).

Sintaxă
type Timer struct {
    C <-chan Time
}

func NewTimer(d Duration) *Timer
func AfterFunc(d Duration, f func()) *Timer
func (t *Timer) Stop() bool
func (t *Timer) Reset(d Duration) bool

Ce face time.Timer

time.NewTimer(d) creează un temporizator care, după d, trimite momentul curent pe canalul t.C, o singură dată. Spre deosebire de time.After, ai acces la obiect, deci îl poți opri sau reporni.

t.Stop() anulează temporizatorul și returnează true dacă l-a oprit înainte să expire (false dacă expirase deja sau era oprit). t.Reset(d) îl pornește din nou cu durata d; returnează true dacă temporizatorul era încă activ. Din Go 1.23, după Stop sau Reset nu mai rămâne nicio valoare veche în canal, deci nu mai trebuie golit manual.

time.AfterFunc(d, f) creează un temporizator care, în loc să scrie pe canal, rulează funcția f într-un goroutine nou. Folosește Stop ca să anulezi apelul.

Ce returnează

NewTimer și AfterFunc: *time.Timer. Stop și Reset: bool, dacă temporizatorul era activ.

Exemple

Exemplul 1: Temporizator oprit înainte să expire

package main

import (
	"fmt"
	"time"
)

func main() {
	t := time.NewTimer(50 * time.Millisecond)
	<-t.C
	fmt.Println("Primul temporizator a expirat")
	fmt.Println("Stop după expirare:", t.Stop())

	alarma := time.NewTimer(time.Hour)
	fmt.Println("Stop înainte de expirare:", alarma.Stop())

	t.Reset(30 * time.Millisecond)
	<-t.C
	fmt.Println("Repornit cu Reset și expirat din nou")
}

Rezultat

Primul temporizator a expirat
Stop după expirare: false
Stop înainte de expirare: true
Repornit cu Reset și expirat din nou

Exemplul 2: Deconectare după inactivitate

Fiecare acțiune a utilizatorului repornește temporizatorul cu Reset. Când utilizatorul nu mai face nimic, temporizatorul expiră.

package main

import (
	"fmt"
	"time"
)

func main() {
	inactiv := 150 * time.Millisecond
	t := time.NewTimer(inactiv)
	actiuni := make(chan string)

	go func() {
		for _, a := range []string{"deschide coșul", "adaugă pâine", "adaugă lapte"} {
			time.Sleep(50 * time.Millisecond)
			actiuni <- a
		}
	}()

	for {
		select {
		case a := <-actiuni:
			fmt.Println("Acțiune:", a)
			t.Reset(inactiv)
		case <-t.C:
			fmt.Println("Sesiune închisă pentru inactivitate")
			return
		}
	}
}

Rezultat

Acțiune: deschide coșul
Acțiune: adaugă pâine
Acțiune: adaugă lapte
Sesiune închisă pentru inactivitate

Exemplul 3: AfterFunc: o funcție rulată mai târziu

package main

import (
	"fmt"
	"time"
)

func main() {
	gata := make(chan bool)
	time.AfterFunc(50*time.Millisecond, func() {
		fmt.Println("Trimit reamintirea pentru Ana")
		gata <- true
	})
	anulat := time.AfterFunc(50*time.Millisecond, func() {
		fmt.Println("Acest mesaj nu apare")
	})
	fmt.Println("Anulat:", anulat.Stop())
	<-gata
}

Rezultat

Anulat: true
Trimit reamintirea pentru Ana

Greșeli frecvente

  • Citești din t.C după ce ai oprit temporizatorul cu Stop: nu va sosi nimic și programul se blochează.
  • Folosești în cod nou trucul vechi if !t.Stop() { <-t.C } înainte de Reset. Din Go 1.23 nu mai este necesar, iar dacă valoarea a fost deja citită, blochează.

Comenzi înrudite

  • time.After: Returnează un canal care primește ora curentă după durata dată; folosit în select pentru limite de timp (timeout).
  • time.Ticker: Un ceas care trimite câte o valoare pe canalul C la fiecare interval; Stop îl oprește, Reset îi schimbă intervalul.
  • context.AfterFunc: Programează funcția f să ruleze (într-un goroutine nou) când contextul este anulat; stop() renunță la ea.