首页 > 其他分享 >golang之context

golang之context

时间:2023-06-16 10:11:13浏览次数:43  
标签:context http Context process ctx golang func

context 用来解决 goroutine 之间退出通知元数据传递的功能。

 

context 使用起来非常方便。源码里对外提供了一个创建根节点 context 的函数:

func Background() Context

 

background 是一个空的 context, 它不能被取消,没有值,也没有超时时间。

有了根节点 context,又提供了四个函数创建子节点 context:

func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
func WithValue(parent Context, key, val interface{}) Context

 

注意:

  1. 不要将 Context 塞到结构体里。直接将 Context 类型作为函数的第一参数,而且一般都命名为 ctx。
  2. 不要向函数传入一个 nil 的 context,如果你实在不知道传什么,标准库给你准备好了一个 context:todo。
  3. 不要把本应该作为函数参数的类型塞到 context 中,context 存储的应该是一些共同的数据。例如:登陆的 session、cookie 等。
  4. 同一个 context 可能会被传递到多个 goroutine,别担心,context 是并发安全的。

 

 

传递共享的数据 #

对于 Web 服务端开发,往往希望将一个请求处理的整个过程串起来,这就非常依赖于 Thread Local(对于 Go 可理解为单个协程所独有) 的变量,而在 Go 语言中并没有这个概念,因此需要在函数调用的时候传递 context。

package main

import (
    "context"
    "fmt"
)

func main() {
    ctx := context.Background()
    process(ctx)

    ctx = context.WithValue(ctx, "traceId", "qcrao-2019")
    process(ctx)
}

func process(ctx context.Context) {
    traceId, ok := ctx.Value("traceId").(string)
    if ok {
        fmt.Printf("process over. trace_id=%s\n", traceId)
    } else {
        fmt.Printf("process over. no trace_id\n")
    }
}


结果
process over. no trace_id
process over. trace_id=qcrao-2019
 

 

 

第一次调用 process 函数时,ctx 是一个空的 context,自然取不出来 traceId。第二次,通过 WithValue 函数创建了一个 context,并赋上了 traceId 这个 key,自然就能取出来传入的 value 值。

当然,现实场景中可能是从一个 HTTP 请求中获取到的 Request-ID。所以,下面这个样例可能更适合:

const requestIDKey int = 0

func WithRequestID(next http.Handler) http.Handler {
    return http.HandlerFunc(
        func(rw http.ResponseWriter, req *http.Request) {
            // 从 header 中提取 request-id
            reqID := req.Header.Get("X-Request-ID")
            // 创建 valueCtx。使用自定义的类型,不容易冲突
            ctx := context.WithValue(
                req.Context(), requestIDKey, reqID)
            
            // 创建新的请求
            req = req.WithContext(ctx)
            
            // 调用 HTTP 处理函数
            next.ServeHTTP(rw, req)
        }
    )
}

// 获取 request-id
func GetRequestID(ctx context.Context) string {
    ctx.Value(requestIDKey).(string)
}

func Handle(rw http.ResponseWriter, req *http.Request) {
    // 拿到 reqId,后面可以记录日志等等
    reqID := GetRequestID(req.Context())
    ...
}

func main() {
    handler := WithRequestID(http.HandlerFunc(Handle))
    http.ListenAndServe("/", handler)
}

 

 

 

 

 

 

 

标签:context,http,Context,process,ctx,golang,func
From: https://www.cnblogs.com/xingxia/p/golang_context.html

相关文章

  • Golang的wire是什么
    Golang的wire是什么了解Golang的wire框架对于构建可维护和可扩展的应用程序至关重要在当今的技术世界中,谷歌的Go语言(Golang)已经成为了许多开发人员的首选语言。Go语言以其简洁性、高效性和并发性而闻名,因此在开发各种类型的应用程序时广受欢迎。随着Go语言的不断发展,出现了许多框......
  • golang之http请求库go-resty
     github: https://github.com/go-resty/resty go-resty特性#go-resty 有很多特性:发起GET,POST,PUT,DELETE,HEAD,PATCH,OPTIONS,etc.请求简单的链式书写自动解析JSON和XML类型的文档上传文件重试功能客户端测试功能RestyclientCustom RootCertif......
  • golang之errors包
    errors包常用方法funcUnwrap(errerror)error//获得err包含下一层错误funcIs(err,targeterror)bool//判断err是否包含targetfuncAs(errerror,targetinterface{})bool//判断err是否为target类型   自定义错误信息err......
  • 简单了解-require.context
    简单了解-require.context1.概念是什么:是一个webpack的api,通过执行require.context函数获取一个特定的上下文,主要用来实现自动化导入模块。作用:将某个文件夹的内容全部导入进来。应用场景:用于全局组件的导入引入vuex的modulesvg图片的引入其他需要同一文件夹多个导入的场......
  • golang对于[]byte数组转string进行比较的优化
    当需要比较两个[]byte数组是否相等时有好几种方案,下面可以看出前三种方案都是优化过的,效率高的方案。packagemainimport( "bytes" "crypto/rand" mr"math/rand" "testing")funcStringEqual(nint,ffunc(a,b[]byte)bool){ buf:=make([]byte,1024) rand.......
  • 【解决一个小问题】golang 的 `-race`选项导致 unsafe代码 panic
    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!cnblogs博客zhihuGithub公众号:一本正经的瞎扯为了提升性能,使用unsafe代码来重构了凯撒加密的代码。代码如下:const( lowerCaseAlphabet="abcdefghijklmnopqrstuvwxyz" upperCaseAlphabet="ABCDEFGHIJKLMN......
  • mac 下Golang 安装Protobuf
    1、安装protobufbrewinstallprotobuf2、检查安装结果protoc--version3、安装golangforprotobuf插件gogetgithub.com/golang/protobuf/protoc-gen-gogoget-u-vgithub.com/golang/protobuf/protoc-gen-gogoget=gitclone+goinstall这里会慢的要死所以我这里采取......
  • go :Multiple-value strconv.Atoi() (int, error) in single-value context
    代码devicePositionType:=strconv.Atoi(info[0]["device_position_type"].(string))报错Multiple-valuestrconv.Atoi()(int,error)insingle-valuecontext这是因为返回的数据有两个参数,代码里只定义了一个,所以代码里需要再加上一个参数,这个参数一般会定义为errdevicePositi......
  • golang 实现cas
    相比sync.WaitGroup里面的互斥锁,cas可以实现无锁等待一组任务执行完成后释放,示例代码如下funcTestCAS(t*testing.T){ varcountint32=10000 fori:=0;i<int(count);{ gofunc(){ deferfunc(){atomic.AddInt32(&count,-1)}() //dosomething //.........
  • golang 闭包,装饰器
    packagemainimport( "fmt" "strings")funcmakeSuffixFunc(suffixstring)func(string)string{ returnfunc(namestring)string{ if!strings.HasSuffix(name,suffix){ returnname+suffix } returnname }}funcmain()......