方式1

第一个技巧的源码保存在 timeOut1.go 中,并分为四部分介绍。

timeOut1.go 的第一部分显示如下代码:

  1. package main
  2. import (
  3. "fmt"
  4. "time"
  5. )

timeOut1.go 第二段代码如下:

  1. func main() {
  2. c1 := make(chan string)
  3. go func () {
  4. time.Sleep(time.Second * 3)
  5. c <- "c1 OK"
  6. }()

time.Sleep() 调用用于模拟函数完成其工作通常需要的时间。在这个例子里,匿名函数以 goroutine 方式执行,它将在大约 3 秒(time.Second * 3)后写消息到 c1 channel。

timeOut1.go 的第三段包含如下代码:

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

time.After() 函数调用的目地是等待指定时间。这个例子中,您不用关心 time.After() 返回的实际值,但实际上 time.After() 函数调用介绍意味着超时了。例子中由于 time.After() 函数指定的值小于上节以 goroutine 方式执行的 time.Sleep() 调用中使用的值,您极有可能得到一个超时信息。

timeOut1.go 的其余代码如下:

  1. c2 := make(chan string)
  2. go func() {
  3. time.Sleep(3 * time.Second)
  4. c2 <- "c2 OK"
  5. }()
  6. select {
  7. case res := <-c2:
  8. fmt.Println(res)
  9. case <- time.After(4 * time.Second):
  10. fmt.Println("timeout c2")
  11. }
  12. }

上面这段代码执行一个 goroutine 并使用 time.After(4 * time.Second) 定义了一个 4 秒的超时期限,由于 time.Sleep() 的调用,这个goroutine 将执行大约 3 秒。如果 time.After(4 * time.Second) 调用的返回在您从 select 块的第一个分支里的 c2 channel 获得值之后,那么就不会超时;否则,将超时!然而,在这个例子中,time.After() 调用的值提供了足够的时间对于 time.Sleep() 调用的返回,因此您极可能不会得到一个超时信息。

执行 timeOut1.go 产生如下输出:

  1. $go run timeOut1.go
  2. timeout c1
  3. c2 OK

正如期望的,第一个 goroutine 没有完成它的工作,而第二个有足够的时间去完成。