Go by Example: Timeouts

Timeouts là rất quan trọng đối với các chương trình kết nối đến tài nguyên bên ngoài hoặc cần giới hạn thời gian thực thi. Việc triển khai timeouts trong Go rất dễ dàng và hiệu quả nhờ vào channels và select.

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

Ví dụ, giả sử chúng ta đang thực hiện gọi một hàm bên ngoài và trả về kết quả của nó trên channel c1 sau 2 giây. Lưu ý rằng channel được lưu vào bộ nhớ đệm, vì vậy gửi/nhận trong goroutine là không chặn. Đây là cách phổ biến để ngăn chặn rò rỉ goroutine trong trường hợp channel không bao giờ được đọc.

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

Đây là cách dùng ‘select’ để quản lý timeout. res := <-c1 chờ giá trị từ c1 và <-time.After chờ giá trị trả về sau 1 giây. Vì select sẽ lựa chọn trường hợp đầu tiên nhận được giá trị trả về, Chúng ta sẽ nhận trường hợp timeout nếu các thao tác khác thực thi lâu hơn 1 giây cho phép. (mất 2 giây để nhận được giá trị từ c1)

    select {

Mất 2 giây để nhận được giá trị từ c1

    case res := <-c1:
        fmt.Println(res)

Mất 1 giây để nhận được giá trị từ time.After

    case <-time.After(1 * time.Second):
        fmt.Println("timeout 1")
    }

Nếu chúng ta nâng timeout lên 3 giây, thì chúng ta sẽ nhận được giá trị từ c2 trước và in ra result 2. [mất 3 giây để nhận được giá trị từ <-time.After(3 * time.Second)]

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

Running this program shows the first operation timing out and the second succeeding.

$ go run timeouts.go 
timeout 1
result 2

Ví dụ tiếp theo: Non-Blocking Channel Operations.