关于context包
如果您浏览一下 context
包点源码,就会认识到它的实现是相当的简单——甚至 Context
类型的实现也非常简单,而 context
包是非常重要的。
Context
类型是一个有四个方法的接口,方法名为 Deadline()
,Done()
,Err()
,Value()
。好消息是您不需要实现 Context
接口的所有方法——您只需要使用如 context.WithCancel()
和 context.WithTimeout()
函数修改 Context
变量就行。
下面是使用 context
包的示例,用 simpleContext.go
文件源码,分六部分来介绍。
simpleContext.go
的第一部分代码如下:
func f1(t int) {
c1 := context.Background()
c1, cancel := context.WithCancel(c1)
defer cancel()
go func(){
time.Sleep(4 * time.Second)
cancel()
}()
f1()
函数只需要一个时延参数,因为其他的都定义在函数里了。注意 变量的类型是 context.CancelFunc
。
您需要调用 context.Background()
函数来初始化一个空 Context
参数。context.WithCancel()
函数使用一个存在的 Context
创建一个子类并执行取消操作。context.WithCancel()
函数也会创建一个 Done
通道,如上面的代码所示当 cancel()
函数被调用时,或者当父 context 的 Done
通道关闭时,它会被关闭。
simpleContext.go
的第三部分包含 f1()
函数的其余部分:
这里您看到了 Context
变量的 Done()
函数的使用。当这个函数被调用时,您有一个取消操作。Context.Done()
的返回值是一个通道,否则您就不能在 select
语句中使用它了。
simpleContext.go
的第四部分如下:
func f2(t int) {
c2 := context.Background()
c2, cancel := context.WithTimeout(c2, time.Duration(t)*time.Second)
defer cancel()
time.Sleep(4 * time.Second)
cancel()
}()
select {
case <-c2.Done():
fmt.Println("f2():", c2.Err())
return
case r := <-time.After(time.Duration(t)*time.Second):
}
return
}
simpleContext.go
的第五部分如下:
上面的代码说明了 context.WithDeadline()
函数的使用,它需要两个参数:Context
变量和一个表示操作将要截止的时间。当期限到了,cancel()
函数自动调用。
simpleContext.go
的最后一段代码如下:
func main() {
fmt.Println("Need a delay!")
return
}
delay, err := strconv.Atoi(os.Args[1])
if err != nil {
fmt.Println(err)
return
}
fmt.Println("Delay:", delay)
f1(delay)
f2(delay)
f3(delay)
执行 simpleContext.go
产生如下输出:
输出较长的行是 time.After()
函数调用的返回值。它们代表程序正常操作。意味着如果该程序执行超时就会立刻被取消。