美文网首页
golang熟练运用context

golang熟练运用context

作者: 化蝶飞618 | 来源:发表于2019-12-31 16:06 被阅读0次

    什么是context

    go从1.7版本之后开始引入了context,它的作用主要是传递上下文信息,像一个大容器,里面也可以存储k-v等数据。之后很多标准库基本上都把函数的第一个参数默认为context参数
    作为天然适合写并发的语言,在处理一个请求适合往往都会开启多个goroutine,那么这些goroutine之前通常需要共享一些共享信息,这个时候context就派上用场了

    context可以运用到哪些场景

    type Context interface {
         //返回一个time.Time,表示当前Context应该结束的时间,ok则表示有结束时间
        Deadline() (deadline time.Time, ok bool)
        //当Context被取消或者超时时候返回的一个close的channel,告诉给context相关的函数要停止当前工作然后返回了。(这个有点像全局广播)
        Done() <-chan struct{}
        //context被取消的原因
        Err() error
        //context实现共享数据存储的地方,是协程安全的
        Value(key interface{}) interface{}
    }
    
    • web编程中,一个请求对应多个goroutine之间的数据交互
    • 超时控制
    • 上下文控制

    context实战应用

    WithCancel实战

    • 多个任务同时工作,通过cancel释放取消信号,所有任务停止
    package main
    
    import (
        "context"
        "fmt"
        "math/rand"
        "time"
    )
    
    var urls chan string
    var preStr = "http"
    
    func main() {
        //定义一个根context
        parent := context.Background()
        urls = make(chan string)
        //创建一个WithCancel
        ctx, cancel := context.WithCancel(parent)
        //任务一下载图片
        downloadPicture(ctx)
        //任务二获取图片地址
        getUrls(ctx)
        time.Sleep(time.Second * 5)
        cancel()
        time.Sleep(time.Second * 10)
    
    
    }
    
    func downloadPicture(ctx context.Context) {
        go func() {
            for {
                select {
                //收到停止信号后,return
                case <-ctx.Done():
                    fmt.Println("downloadPicture stop")
                    return
                case url := <-urls:
                    fmt.Println("download page url=" + url)
                }
            }
        }()
    }
    
    func getUrls(ctx context.Context) {
        go func() {
            for {
                select {
                case <-ctx.Done():
                    fmt.Println("getUrls stop")
                    return
                default:
                    num := rand.Int31()
                    url := fmt.Sprintf("url=%d", num)
                    urls <- url
                    time.Sleep(time.Second)
                }
            }
        }()
    }
    

    WithDeadline&WithTimeout实战

    • 源码中,其实WithTimeout内部就是调用的WithDeadline,两者的效果是一样的
    package main
    
    import (
        "context"
        "fmt"
        "math/rand"
        "time"
    )
    var urls1 chan string
    func main()  {
        //定义一个根context
        parent := context.Background()
        urls1 = make(chan string)
            //ctx, cancel := context.WithDeadline(parent,time.Now().Add(5))
        ctx, cancel := context.WithTimeout(parent,time.Second * 5)
        DownloadPicture1(ctx)
        GetUrls1(ctx)
        time.Sleep(time.Second * 10)
        defer cancel()
    }
    
    func DownloadPicture1(ctx context.Context) {
        go func() {
            for {
                select {
                //收到停止信号后,return
                case <-ctx.Done():
                    fmt.Println("downloadPicture stop")
                    return
                case url := <-urls1:
                    fmt.Println("download page url=" + url)
                }
            }
        }()
    }
    
    func GetUrls1(ctx context.Context) {
        go func() {
            for {
                select {
                case <-ctx.Done():
                    fmt.Println("getUrls stop")
                    return
                default:
                    num := rand.Int31()
                    url := fmt.Sprintf("url=%d", num)
                    urls1 <- url
                    time.Sleep(time.Second)
                }
            }
        }()
    }
    

    WithValue

    package main
    
    import (
        "context"
        "fmt"
    )
    
    func main()  {
        //定义一个根context
        parent := context.Background()
        //添加k-v值
        ctx := context.WithValue(parent,"test","testval")
        //获取val值
        val := ctx.Value("test").(string)
        fmt.Println(val)
    
    }
    
    

    相关文章

      网友评论

          本文标题:golang熟练运用context

          本文链接:https://www.haomeiwen.com/subject/fvzmoctx.html