Go за Прикладом: Тайм-аути (Timeouts)

Work in Progress / Сайт в процесі розробки

Таймаути важливі для програм що спілкуються з зовнішніми ресурсами або які враховують час виконання. Впровадження таймаутів в Go задача проста та елегантна, і все це завдяки каналам та select.

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

Для нашого прикладу, припустимо ми виконуємо виклик назовні що повертає результати каналом c1 через 2 секунди.

    c1 := make(chan string, 1)
    go func() {
        time.Sleep(2 * time.Second)
        c1 <- "результат 1"
    }()

А тут select імплементує таймаут. res := <-c1 чекає на повідомлення і <-Time.After теж чекає 1 секунду, на повідомлення з каналу що сам і створив. Оскільки select опрацьовує перший готовий виклак, буде опрацьований виклик з time.After оськільки він буде виконаний за 1 секунду, напротивагу 2-ом секундам виконання горутини, що писатиме в c1.

    select {
    case res := <-c1:
        fmt.Println(res)
    case <-time.After(1 * time.Second):
        fmt.Println("таймаут 1")
    }

Якщо ми дозволимо довший таймаут в 3 секунди, тоді ми зможемо отримати та надрукувати результат з каналу c2.

    c2 := make(chan string, 1)
    go func() {
        time.Sleep(2 * time.Second)
        c2 <- "результат 2"
    }()
    select {
    case res := <-c2:
        fmt.Println(res)
    case <-time.After(3 * time.Second):
        fmt.Println("таймаут 2")
    }
}

Запуск цієї программи покаже що у першої операції витік час, а друга завершилась успішно.

$ go run timeouts.go
таймаут 1
результат 2

Використання цього шоблону напряму залежить від обміну результатами через канали. Це непогана ідея бо і інші важливі особливості Go залежать від каналів та select. Ми розглянемо це два приклада: хронометри та маятники.

Наступний приклад: Не Блокуючі Операції на Каналах.