方式1

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

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

package main

import (
    "fmt"
    "time"
)

timeOut1.go 第二段代码如下:

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

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

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

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

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

timeOut1.go 的其余代码如下:

    c2 := make(chan string)
    go func() {
        time.Sleep(3 * time.Second)
        c2 <- "c2 OK"
    }()

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

上面这段代码执行一个 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 产生如下输出:

$go run timeOut1.go
timeout c1
c2 OK

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

最后编辑: kuteng  文档更新时间: 2021-03-27 20:14   作者:kuteng