golang-context(上下文管理)

context 上下文管理

主要功能:
- 全局变量设置
- 通知goroutine退出

通知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-b18d27cdf201

主程序完成后自动关闭所有的goroutine

context.WithCanceln 自动通知goroutine退出的原理很简单,

  1. 就是在cancle()的时候,自动向chan发送一个信号数据,
  2. 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)
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值