type Context
type Context interface {
//Done方法返回一个channel,当Context取消或到达截至时间时,该channel即会关闭
Done() <-chan struct{}
//Err方法返回取消的错误原因,因为什么Context被取消。
Err() error
//Deadline方法是获取设置的截止时间的意思
//第一个返回式是截止时间,到了这个时间点,Context会自动发起取消请求;
//第二个返回值ok==false时表示没有设置截止时间,如果需要取消的话,需要调用取消函数进行取消。
Deadline() (deadline time.Time, ok bool)
//Value方法获取该Context上绑定的值
//一个键值对,所以要通过一个Key才可以获取对应的值,这个值是线程安全的
Value(key interface{}) interface{}
}
func TODO() Context
- TODO返回一个非nil的空上下文。代码应该使用上下文。当不清楚要使用哪个上下文或它还不可用时(因为周围的函数还没有扩展到接受上下文参数),TODO。TODO由静态分析工具识别,该工具确定上下文是否在程序中正确传播。
func Background() Context
- 返回一个非nil的空上下文。它从未被取消,没有值,也没有截止日期。它通常由主函数、初始化和测试使用,并作为传入请求的顶级上下文
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
- 返回带有新Done通道的父进程的副本。当调用返回的cancel函数或当关闭父上下文的Done通道时,将关闭返回上下文的Done通道,无论先发生什么情况。 ```go package main
import ( “context” “log” “os” “time” )
var Logg *log.Logger
func MyHandle() { ctx,cancel:=context.WithCancel(context.Background()) go Do(ctx) time.Sleep(time.Second*10) cancel() } func Do(ctx context.Context){ for { time.Sleep(time.Second) select { case <- ctx.Done(): Logg.Printf(“done”) return default: Logg.Printf(“work”) } } } func main() { Logg =log.New(os.Stdout,””,log.Ltime) MyHandle() Logg.Printf(“down”) } 13:15:13 work 13:15:14 work 13:15:15 work 13:15:16 work 13:15:17 work 13:15:18 work 13:15:19 work 13:15:20 work 13:15:21 work 13:15:22 down
func WithDeadline(parent [Context](https://studygolang.com/static/pkgdoc/pkg/context.htm#Context), deadline [time](https://studygolang.com/time).[Time](https://studygolang.com/time#Time)) ([Context](https://studygolang.com/static/pkgdoc/pkg/context.htm#Context), [CancelFunc](https://studygolang.com/static/pkgdoc/pkg/context.htm#CancelFunc))
- 设置超时时间,绝对时间
func WithTimeout(parent [Context](https://studygolang.com/static/pkgdoc/pkg/context.htm#Context), timeout [time](https://studygolang.com/time).[Duration](https://studygolang.com/time#Duration)) ([Context](https://studygolang.com/static/pkgdoc/pkg/context.htm#Context), [CancelFunc](https://studygolang.com/static/pkgdoc/pkg/context.htm#CancelFunc))
- 设置超时时间,相对时间
func WithValue(parent [Context](https://studygolang.com/static/pkgdoc/pkg/context.htm#Context), key, val interface{}) [Context](https://studygolang.com/static/pkgdoc/pkg/context.htm#Context)
- 传值,注意类型是空接口,在使用时要断言
- 作用:设置共享参数,跟踪子系统的执行情况
- 提供的键必须具有可比性,并且不应该是字符串类型或任何其他内置类型,以避免使用上下文的包之间的冲突。
- WithValue的用户应该为键定义自己的类型。
- 为了避免在为接口{}赋值时进行分配,上下文键通常有具体的类型结构体{}。或者,导出的上下文关键变量的静态类型应该是point
```go
package main
import (
"context"
"fmt"
"math/rand"
"time"
)
const(
Elapsed ="elapsed"
)
func MyHandle() {
ctx:=context.WithValue(context.Background(),Elapsed,time.Now())
rand.Seed(time.Now().UnixNano())
a(ctx)
}
func a(ctx context.Context){
time.Sleep(time.Duration(rand.Int63n(3)) * time.Second)
elapsed := time.Since(ctx.Value(Elapsed).(time.Time))
fmt.Printf("traceid:%v,func:%v\n",elapsed,"a")
b(ctx)
}
func b(ctx context.Context){
time.Sleep(time.Duration(rand.Int63n(3)) * time.Second)
elapsed := time.Since(ctx.Value(Elapsed).(time.Time))
fmt.Printf("traceid:%v,func:%v\n",elapsed,"b")
c(ctx)
}
func c(ctx context.Context){
time.Sleep(time.Duration(rand.Int63n(3)) * time.Second)
elapsed := time.Since(ctx.Value(Elapsed).(time.Time))
fmt.Printf("traceid:%v,func:%v\n",elapsed,"c")
}
func main() {
MyHandle()
}
traceid:1.0005927s,func:a
traceid:3.0009336s,func:b
traceid:4.0012555s,func:c
cancel方法源码
不必担心cancel多次被调用的问题,他的内部已经做了判断
func (c *cancelCtx) cancel(removeFromParent bool, err error) {
if err == nil {
panic("context: internal error: missing cancel error")
}
c.mu.Lock()
if c.err != nil {
c.mu.Unlock()
return // already canceled
}
c.err = err
if c.done == nil {
c.done = closedchan
} else {
close(c.done)
}
for child := range c.children {
// NOTE: acquiring the child's lock while holding parent's lock.
child.cancel(false, err)
}
c.children = nil
c.mu.Unlock()
if removeFromParent {
removeChild(c.Context, c)
}
}
例子一:按设置的时间自动关闭
package main
import (
"context"
"log"
"os"
"time"
)
var Logg *log.Logger
var StatusChan = make(chan int)
func MyHandle() {
ctx,_:=context.WithDeadline(context.Background(),time.Now().Add(time.Second*5))
//ctx,_:=context.WithTimeout(context.Background(),time.Second*5)
go Do(ctx)
}
func Do(ctx context.Context){
for {
time.Sleep(time.Second)
select {
case <- ctx.Done():
Logg.Printf("done")
StatusChan<-1
default:
Logg.Printf("work")
}
}
}
func main() {
Logg =log.New(os.Stdout,"",log.Ltime)
MyHandle()
<- StatusChan
Logg.Printf("down")
}
13:45:41 work
13:45:42 work
13:45:43 work
13:45:44 work
13:45:45 done
13:45:45 down
例子二:在设置的时间前,主动关闭
package main
import (
"context"
"log"
"os"
"time"
)
var Logg *log.Logger
func MyHandle() {
ctx,cancel:=context.WithDeadline(context.Background(),time.Now().Add(time.Second*5))
//ctx,_:=context.WithTimeout(context.Background(),time.Second*5)
go Do(ctx)
select {
case <-time.After(time.Second*3):
cancel()
}
}
func Do(ctx context.Context){
for {
time.Sleep(time.Second)
select {
case <- ctx.Done():
Logg.Printf("done")
default:
Logg.Printf("work")
}
}
}
func main() {
Logg =log.New(os.Stdout,"",log.Ltime)
MyHandle()
Logg.Printf("down")
}
13:44:09 work
13:44:10 work
13:44:11 down