深入理解Golang中的Context包

context.Context是Go语言中独特的设计,在其他编程语言中我们很少见到类似的概念。context.Context深度支持Golang的高并发。

1. Goroutine和Channel

在理解context包之前,应该首先熟悉Goroutine和Channel,能加深对context的理解。

1.1 Goroutine

Goroutine是一个轻量级的执行线程,多个Goroutine比一个线程轻量,所以管理Goroutine消耗的资源相对更少。Goroutine是Go中最基本的执行单元,每一个Go程序至少有一个Goroutine:主Goroutine。程序启动时会自动创建。为了能更好的理解Goroutine,先来看一看线程Thread与协程Coroutine的概念。

  • 线程(Thread)
    线程是一种轻量级进程,是CPU调度的最小单位。一个标准的线程由线程ID当前指令指针(PC)寄存器集合堆栈组成。线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属于一个进程的其他线程共享进程所拥有的全部资源。线程拥有自己独立的栈和共享的堆,共享堆,不共享栈 线 程 的 切 换 一 般 由 操 作 系 统 调 度 \color{red}{线程的切换一般由操作系统调度} 线
  • 协程(Coroutine)
    协程又称为微线程,与子例程一样,协程也是一种程序组建,相对子例程而言,协程更为灵活,但在实践中使用没有子例程那样广泛。和线程类似,共享堆,不共享栈, 协 程 的 切 换 一 般 由 程 序 员 在 代 码 中 显 式 控 制 \color{red}{协程的切换一般由程序员在代码中显式控制} 。他避免了上下文切换的额外耗费,兼顾了多线程的优点,简化了高并发程序的复杂。

Goroutine和其他语言的协程(coroutine)在使用方式上类似,但从字面意义上来看不同(一个是Goroutine,一个是coroutine),再就是协程是一种协作任务控制机制,在最简单的意义上,协程不是并发的,而Goroutine支持并发的。因此Goroutine可以理解为一种Go语言的协程。同时,Gorotine可以运行在一个或多个线程上

1.2 使用Goroutine示例

func Hello()  {
   
    fmt.Println("hello everybody , I'm lineshen")
}

func main()  {
   
    go Hello()
    fmt.Println("Golang-Gorontine Example")
}

在该代码片段中,使用go又开启了一个Goroutine执行Hello方法,其运行结果如下:

Golang-Gorontine Example

从执行结果上,直观的看,我们的程序似乎没有执行Goroutine的Hello方法。出现这个问题的原因是我们启动的主Goroutine在main执行完就退出了,所以为了main等待Hello-Goroutine执行完,就需要一些方法,让Hello-Goroutine告诉main执行完了,这里就需要通道Channel了。

1.3 Channel

Channel就是多个Goroutine 之间的沟通渠道。当我们想要将结果或错误,或任何其他类型的信息从一个 goroutine 传递到另一个 goroutine 时就可以使用通道。通道是有类型的,可以是 int 类型的通道接收整数或错误类型的接收错误等。

假设有个 int 类型的通道 ch,如果想发一些信息到这个通道,语法是 ch <- 1,如果想从这个通道接收一些信息,语法就是 var := <-ch。这将从这个通道接收并存储值到 var 变量。

通过改善1.2中的代码片段,证明通道的使用确保了 goroutine 执行完成并将值返回给 main 。

func Hello(ch chan int)  {
   
    fmt.Println("hello everybody , I'm lineshen")
    ch <- 1
}

func main()  {
   
    ch := make(chan int)
    go Hello(ch)
    <-ch
    fmt.Println("Golang-Gorontine Example")
}

执行结果如下:

hello everybody , I'm lineshen
Golang-Gorontine Example

这里我们使用通道进行等待,这样main就会等待Hello-Goroutine执行完。熟悉了Goroutine、Channel的概念了,就很好理解Context了。

2. Context应用场景

熟悉了Goroutine、Channel的概念,先看一个请求服务场景示例:

func main()  {
   
    http.HandleFunc("/", SayHello) // 设置访问的路由
    log.Fatalln(http.ListenAndServe(":8080",nil))
}

func SayHello(writer http.ResponseWriter, request *http.Request)  {
   
    fmt.Println(
  • 13
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Go语言context提供了一种在跨多个goroutine之间传递请求范围数据、取消信号和截止时间的方法。它是Go语言处理并发和并行的重要工具之一。 Context类型是context的核心类型,它代表了一个请求的上下文。通过创建一个Context对象,我们可以在程序传递请求相关的数据和信号。Context对象可以被用于控制goroutine的生命周期,以及在需要时取消或超时处理。 Context含了一些重要的方法和属性,例如: 1. WithCancel(parent Context) (ctx Context, cancelFunc CancelFunc):创建一个可取消的Context,并返回一个取消函数。当调用取消函数时,所有从该Context派生的子Context都会被取消。 2. WithDeadline(parent Context, deadline time.Time) (ctx Context, cancelFunc CancelFunc):创建一个带有截止时间的Context。当截止时间到达时,所有从该Context派生的子Context都会被取消。 3. WithTimeout(parent Context, timeout time.Duration) (ctx Context, cancelFunc CancelFunc):创建一个带有超时时间的Context。当超过指定的时间后,所有从该Context派生的子Context都会被取消。 4. WithValue(parent Context, key interface{}, value interface{}) Context:创建一个带有键值对的Context。这个方法可以用来传递请求范围的数据。 使用context可以有效地管理并发操作,避免资源泄漏和无限等待的情况。在编写并发代码时,合理使用context可以提高程序的可读性和可维护性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值