Go by Example: Timeout

I timeout sono importanti per programmi che si connettono a risorse esterne o che altrimenti necessitano di limitare il tempo di esecuzione. Implementare timeout in Go è facile ed elegante grazie ai canali e select.

package main
import (
    "fmt"
    "time"
)
func main() {

Per il nostro esempio, supponiamo di eseguire una chiamata esterna che restituisce il suo risultato su un canale c1 dopo 2s. Nota che il canale è bufferizzato, quindi l’invio nella goroutine è non-bloccante. Questo è un pattern comune per prevenire leak di goroutine nel caso in cui il canale non venga mai letto.

    c1 := make(chan string, 1)
    go func() {
        time.Sleep(2 * time.Second)
        c1 <- "result 1"
    }()

Ecco il select che implementa un timeout. res := <-c1 aspetta il risultato e <-time.After aspetta che venga inviato un valore dopo il timeout di 1s. Poiché select procede con la prima ricezione che è pronta, prenderemo il caso timeout se l’operazione impiega più di 1s consentito.

    select {
    case res := <-c1:
        fmt.Println(res)
    case <-time.After(1 * time.Second):
        fmt.Println("timeout 1")
    }

Se permettiamo un timeout più lungo di 3s, allora la ricezione da c2 avrà successo e stamperemo il risultato.

    c2 := make(chan string, 1)
    go func() {
        time.Sleep(2 * time.Second)
        c2 <- "result 2"
    }()
    select {
    case res := <-c2:
        fmt.Println(res)
    case <-time.After(3 * time.Second):
        fmt.Println("timeout 2")
    }
}

Eseguendo questo programma vediamo la prima operazione andare in timeout e la seconda avere successo.

$ go run timeout.go 
timeout 1
result 2

Prossimo esempio: .