主要功能: - 全局变量设置 - 通知goroutine退出
使用context.Done()通道是否有数据判断超时时间
如果到达超时时间,ctx就会往超时通道放一个数据ctx.Done()是从超时通道中获取一个消息,如果获取到了,说明超时时间已经到了。然后执行该请求的关闭操作 package main import ( "io/ioutil" "time" "net/http" "context" "fmt" ) type Result struct{ r *http.Response err error } func process(){ // 生成一个context超时多对象 ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) // 最后关闭这个对象 defer cancel() //生成http的相关对象,和返回结果的管道 tr := &http.Transport{} client := &http.Client{Transport: tr} resultChan := make(chan Result, 1) // 生成一个http请求的对象 req, err := http.NewRequest("GET", "https://www.google.com.hk", nil) if err != nil{ fmt.Println("http request failed, err:", err) return } // 使用goroutine 执行开始请求并把结果返回到resultChan通道中 go func(){ resp, err := client.Do(req) pack := Result{r: resp, err: err} resultChan <- pack }() // 检查两个通道判断请求的结果 // ctx.Done()是一个超时的通道,如果之行后就会在指定的超时时间点放入一个消息到这个通道中 // resultChan 是请求结果的通道,如果这个通道有数据说明请求结果完成。 select { case <- ctx.Done(): // 是否能在超时时间通道获取数据,如果获取到就直接把该请求取消。 tr.CancelRequest(req) res := <- resultChan fmt.Println("Time out, err:", res.err) case res := <- resultChan : // 如果有数据打印请求的数据 defer res.r.Body.Close() out, _ := ioutil.ReadAll(res.r.Body) fmt.Printf("server Respones :%s", out) } } func main(){ process() }编译并运行:
$ go build go_dev/day12/exercise/context $ ./context Time out, err: Get https://www.google.com.hk: net/http: request canceled while waiting for connection网址更改为http://www.baidu.com 重新编译运行
$ go build go_dev/day12/exercise/context $ ./context server Respones :<!DOCTYPE html> <!--STATUS OK--> 等html源代码继承是在实例化新的对象时,引用已有的对象
package main import ( "context" "fmt" ) func process(ctx context.Context) { ret, ok := ctx.Value("trace_id").(int) if !ok { ret = 654321 } fmt.Printf("ret:%d\n", ret) user_id, ok := ctx.Value("user_id").(string) if !ok { fmt.Println("Can't get user_id") } fmt.Println("user_id:", user_id) return } func main() { // context.Background() 可以理解为一个基类 ctx := context.WithValue(context.Background(), "trace_id", 123456) // 之后再设置可以引用上面的ctx(继承) ctx = context.WithValue(ctx, "user_id", "9fd14d74-9fde-48ff-a060-b18d27cdf201") process(ctx) }变异并运行:
$ go build go_dev/day12/exercise/ctx_value $ ./ctx_value ret:123456 user_id: 9fd14d74-9fde-48ff-a060-b18d27cdf201context.WithCanceln 自动通知goroutine退出的原理很简单,
就是在cancle()的时候,自动向chan发送一个信号数据,goroutine通过ctx.Done()获取数据后自动退出 package main import ( "time" "fmt" "context" ) func gen(ctx context.Context) <-chan int{ dst := make(chan int) n := 1 go func(){ for{ select{ case <- ctx.Done(): fmt.Println(n, "exit") return case dst <- n: n++ } } }() return dst } func test(){ ctx, cancel := context.WithCancel(context.Background()) defer cancel() intChan := gen(ctx) for n := range intChan{ fmt.Println(n) if n == 5{ break } } } func main(){ test() time.Sleep(time.Hour) }