Timers
Un timer è una struct complessa, comprendente un campo channel C.
Il timer viene creato con la funzione NewTimer del package time, che lo alloca in memoria dinamica.
Il parametro di creazione è un tempo, allo scadere del quale viene posto un valore sul channel C del timer.
Anche la funzione After del package time si comporta in modo simile, ma sottilmente diverso. After è un channel che viene riempito allo scadere del suo argomento.
Mentre un timer è interrompibile, il canale After non lo è. After serve per un ritardo temporale locale, un timer è una sveglia assoluta.
Esempio
(320timers.go):
package main
import "time"
import "fmt"
func main() {
// Un timer è un evento a scadenza temporale futura
// Un timer ha un channel C che ha un elemento
// allo scadere del timer
timer1 := time.NewTimer(time.Second)
fmt.Println("main: timer 1 set to 1 second")
// La seguente è bloccante
<-timer1.C
fmt.Println("main: timer 1 expired")
// Un timer può essere fermato prima dello scadere
// a differenza di time.Sleep
timer2 := time.NewTimer(10 * time.Second)
fmt.Println("main: timer 2 set to 10 seconds")
// La goroutine attende il timer2 e
// segnala ogni secondo che passa
go func() {
i := 0
for {
select {
case <-timer2.C:
fmt.Println("go: timer 2 expired")
return
case <-time.After(time.Second):
i++
fmt.Printf("go: still here after %d sec\n", i)
}
}
}()
//Attende 3 secondi prima di fermare il timer
fmt.Println("main: waiting 5 seconds before stopping timer2")
<-time.After(5 * time.Second)
// Ferma timer2
stop2 := timer2.Stop()
// timer2.Stop ritorna un booleano indicante successo
if stop2 {
fmt.Println("main: timer 2 stopped")
}
// Quando un timer è fermato le goroutine bloccate
// sul timer non vengono terminate
// E' possibile risettare un timer
timer2.Reset(3 * time.Second)
fmt.Println("main: timer 2 reset to 3 second")
fmt.Println("main: waiting 5 seconds before exiting")
<-time.After(5 * time.Second)
fmt.Println("main: exiting now")
}
Ad un timer si può applicare la funzione Stop: il timer continua ad esistere, ma il suo tempo di scatto è ora infinito.
Con la funzione Reset il timer può essere fatto ripartire con un tempo diverso di scatto.
Tutto il codice che attendeva in lettura sul canale Cdel timer si comporta di conseguenza.
Distruzione di timer
Un timer viene automaticamente distrutto dopo lo scatto e quindi il primo codice che lo legge vince.
Questo è dimostrato dal seguente programma:
(321-timer-two.go):
package main
import (
"fmt"
"time"
)
func main() {
tim := time.NewTimer(3 * time.Second)
go func() {
i := 0
for {
select {
case <-tim.C:
fmt.Println("go1: timer expired")
return
case <-time.After(time.Second):
i++
fmt.Printf("go1: still here after %d sec\n", i)
}
}
}()
go func() {
i := 0
for {
select {
case <-tim.C:
fmt.Println("go2: timer expired")
return
case <-time.After(time.Second):
i++
fmt.Printf("go2: still here after %d sec\n", i)
}
}
}()
<-time.After(10 * time.Second)
fmt.Println("main: exiting now")
}
E' aleatorio se sia prima go1 o go2 a ricevere il segnale dal timer.
Evidentemente o non più di una goroutine deve attendere lo stesso timer, oppure abbiamo bisogno di informare le altre goroutines dello scatto avvenuto.