Golang Go语言 context 简介(1)

发布于 1周前 作者 yibo5220 来自 Go语言

Golang Go语言 context 简介(1)

这个系列主要聊下 context 的出发点,带来了哪些便利的地方,常用 API,以及源代码分析

很多童鞋忽略的问题

API 服务是很多童鞋开发过的套路,从 API 取得数据或者控制字段,查询数据库返回业务数据。 那好,问题来了,如果 http client(curl 或者浏览器)在数据没有返回的过程中,异常中止了。你的 API 服务是不是还在傻傻的查询呢? 先来个伪代码模拟,下面会用 fmt.Printf+time.Sleep 模拟数据库查询操作。

package main

import ( “fmt” “github.com/gin-gonic/gin” “time” )

func main() {

router := gin.Default()
router.POST("/", func(c *gin.Context) {

    //模拟操作数据库
    for i := 0; i < 200; i++ {
        fmt.Printf("read db\n")
        time.Sleep(time.Second * 1)
    }
})  

router.Run()

} // curl -X POST 127.0.0.1:8080/ // 你会发现如果客户段 ctrl+c 后,还会不停打印 read db,直到计算器结束。

调研 http.Request 数据结构

上面的资源浪费有没有办法优化?先瞄下 http.Request 源代码。好像有个 context 的东西还挺有意思的。

type Request struct {
    // ctx is either the client or server context. It should only
    // be modified via copying the whole Request using WithContext.
    // It is unexported to prevent people from using Context wrong
    // and mutating the contexts held by callers of the same request.
    ctx context.Context
}

// Context returns the request’s context. To change the context, use // WithContext. // // The returned context is always non-nil; it defaults to the // background context. // // For outgoing client requests, the context controls cancelation. // // For incoming server requests, the context is canceled when the // client’s connection closes, the request is canceled (with HTTP/2), // or when the ServeHTTP method returns. func (r *Request) Context() context.Context { if r.ctx != nil { return r.ctx } return context.Background() }

改造资源浪费代码

package main

import ( “fmt” “github.com/gin-gonic/gin” “time” )

func main() {

router := gin.Default()
router.POST("/", func(c *gin.Context) {

    //模拟操作数据库
    ctx := c.Request.Context()
    for i := 0; i < 200; i++ {
        select {
        case <-ctx.Done(): // 新增加的关键代码
            fmt.Printf("found client ctrl+c\n")
            return
        default:
            fmt.Printf("read db\n")
        }
        time.Sleep(time.Second * 1)
    }
})

router.Run()

}

// curl -X POST 127.0.0.1:8080/ // 你会发现如果客户段 ctrl+c 后,已经不打印出来 read db。

ok,完美解决资源浪费的问题。 还有更多玩法,下篇介绍。

我的 github

https://github.com/guonaihong/gout


更多关于Golang Go语言 context 简介(1)的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

13 回复

request with context go1.7 出的功能 是很好用

更多关于Golang Go语言 context 简介(1)的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


是的好用,最重要的是 context 已经被官方扶正,后面一些并发套路都要用 context 的设计模式了。

一个连续的过程该等多久还是得等多久,比如同步查数据库要花 10 分

楼主的语文需要重修。

可有重修的门路?

兄弟,没太明白提出的问题。。。

赞,昨天因为在自己写接口的时候发现读库的时候有个 query 跟 quertContext 两个方法,于是去查了一下 context 的相关知识,只是有了解还不太会用

其实我一直没有理解 TODO 以及 backGround 两个使用的特点,什么时候用哪个

todo 就是暂时作为父 context 后续可能会改,另一个就是父 context 不会改了


从实现上来看没啥区别,都是从 emptyCtx 构造出来。更多的区别还是字面意思。
go<br>var (<br> background = new(emptyCtx)<br> todo = new(emptyCtx)<br>)<br><br>// Background returns a non-nil, empty Context. It is never canceled, has no<br>// values, and has no deadline. It is typically used by the main function,<br>// initialization, and tests, and as the top-level Context for incoming<br>// requests.<br>func Background() Context {<br> return background<br>}<br><br>// TODO returns a non-nil, empty Context. Code should use context.TODO when<br>// it's unclear which Context to use or it is not yet available (because the<br>// surrounding function has not yet been extended to accept a Context<br>// parameter).<br>func TODO() Context {<br> return todo<br>}<br>

楼主以前是不是写 PHP 的啊?

以前写 linux c 的。怎么了?

以下是对“Golang Go语言 context 简介”的回复:

在Go语言中,context(上下文)是一个非常重要的概念,它主要用于在多个goroutine之间传递请求特定任务的截止日期、取消信号以及其他请求范围的值。

context本质上是一个接口,定义了四个方法:Deadline()、Done()、Err()和Value(key interface{})。通过这四个方法,context可以在goroutine之间传递控制信号和数据,实现任务的同步、取消和超时控制等功能。

在实际应用中,context的使用非常广泛。例如,在处理HTTP请求时,可以使用context来传递请求的截止日期和取消信号,以便在请求处理过程中及时响应客户端的取消操作或超时限制。此外,在数据库操作中,context也可以用来控制查询的超时时间和取消操作,以避免资源占用过多和数据库连接泄漏等问题。

context的创建和传递也非常灵活。可以通过context.Background()或context.TODO()创建一个空的context作为根节点,然后通过context.WithCancel()、context.WithDeadline()和context.WithTimeout()等方法创建带有取消功能、截止日期或超时限制的子context,并将它们传递给需要的goroutine。

总之,context是Go语言中处理并发编程时非常有用的工具,它可以帮助开发者更好地管理goroutine之间的控制信号和数据传递,提高程序的可靠性和可维护性。

回到顶部