Go в примерах: Тайм-ауты (Timeouts)

Тайм-ауты важны для программ, которые подключаются к внешним ресурсам или которым необходимо ограничить время выполнения. Тайм-ауты в Go реализуются легко и элегантно благодаря каналам и select‘ам.

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

В нашем примере предположим, что мы выполняем внешний вызов, который возвращает результат на канале c1 через 2с. Обратите внимание, что канал буферизован, поэтому отправка в goroutine неблокирующая. Это обычная схема предотвращения утечек горутин в случае, если канал никогда не читается.ё

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

Вот select, реализующий тайм-аут. res := <-c1 ожидает результата, а <-Time.After ожидает значения, которое будет отправлено после истечения времени ожидания 1с. Поскольку select продолжает работу с первым полученным запросом, мы возьмем тайм-аут, если операция займет больше разрешенных 1с.

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

Если мы допустим время ожидания более 3с, то получение от c2 будет успешным, и мы распечатаем результат.

    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")
    }
}

Запуск этой программы показывает время ожидания первой и второй успешной операции.

$ go run timeouts.go 
timeout 1
result 2

Следующий пример: Неблокируемые операции в каналах (Non-Blocking Channel Operations).