_Timeouts_ are important for programs that connect to external resources or that otherwise need to bound execution time. Implementing timeouts in Go is easy and elegant thanks to channels and `select`. | ||
package main |
||
import ( |
||
"fmt" |
||
"time" |
||
) |
||
func main() { |
||
For our example, suppose we're executing an external call that returns its result on a channel `c1` after 2s. Note that the channel is buffered, so the send in the goroutine is nonblocking. This is a common pattern to prevent goroutine leaks in case the channel is never read. | c1 := make(chan string, 1) |
|
go func() { |
||
time.Sleep(2 * time.Second) |
||
c1 <- "result 1" |
||
}() |
||
Here's the `select` implementing a timeout. `res := <-c1` awaits the result and `<-time.After` awaits a value to be sent after the timeout of 1s. Since `select` proceeds with the first receive that's ready, we'll take the timeout case if the operation takes more than the allowed 1s. | select { |
|
case res := <-c1: |
||
fmt.Println(res) |
result 1 |
|
case <-time.After(1 * time.Second): |
||
fmt.Println("timeout 1") |
timeout 1 |
|
} |
||
If we allow a longer timeout of 3s, then the receive from `c2` will succeed and we'll print the result. | c2 := make(chan string, 1) |
|
go func() { |
||
time.Sleep(2 * time.Second) |
||
c2 <- "result 2" |
||
}() |
||
select { |
||
case res := <-c2: |
||
fmt.Println(res) |
result 2 |
|
case <-time.After(3 * time.Second): |
||
fmt.Println("timeout 2") |
||
} |
||
} |