golang熟练运用context

化蝶飞618 · · 950 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

什么是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)

}


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:化蝶飞618

查看原文:golang熟练运用context

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

950 次点击  
加入收藏 微博
2 回复  |  直到 2020-01-01 21:40:03
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传