Timeout
#
// I _Timeout_ sono fondamentali per i programmi che si
// connettono a risorse esterne o che hanno comunque
// bisogno di limitare il tempo d'esecuzione.
// Implementare i timeout in Go è semplice grazie ai
// channel e al costrutto `select`.
package main
import "time"
import "fmt"
func main() {
// Ai fini del nostro esempio, supponiamo di star
// eseguendo una chiamata esterna che restituisce il suo
// risultato sul channel `c1` dopo 2 secondi.
c1 := make(chan string, 1)
go func() {
time.Sleep(time.Second * 2)
c1 <- "risultato 1"
}()
// Qui mostriamo il `select` che implementa un timeout.
// Il comando `res := <-c1` attende il risultato della funzione
// mentre il comando `<-Time.After` emette un risultato dopo
// un timeout di 1 secondo.
// Dal momento che il comando `select` procede con il primo
// canale per cui è disponibile un valore, eseguiremo il caso
// del timout se la nostra chiamata esterna richiede più di
// 1 secondo.
select {
case res := <-c1:
fmt.Println(res)
case <-time.After(time.Second * 1):
fmt.Println("timeout 1")
}
// In questo caso possiamo vedere come impostare un timeout di
// 3 secondi sia sufficiente a far restituire la nostra goroutine
// che scrive sul canale `c2`. Riusciremo infatti a vedere il
// risultato a schermo e a non far scattare il timeout.
c2 := make(chan string, 1)
go func() {
time.Sleep(time.Second * 2)
c2 <- "risultato 2"
}()
select {
case res := <-c2:
fmt.Println(res)
case <-time.After(time.Second * 3):
fmt.Println("timeout 2")
}
}
# Se si esegue questo programma si potrà notare come
# la prima operazione andrà in timeout, mentre la seconda
# verrà eseguita correttamente.
$ go run timeouts.go
timeout 1
risultato 2
# Usare questo pattern con il `select` per implementare
# i timeout e la comunicazione attraverso i channel
# risulta essere particolarmente vantaggioso.
# Svariate altre funzionalità di Go sono basate su
# channel e `select`, vedremo due esempi di questo a
# breve: i _timer_ e i _ticker_.