Go语言学习笔记

go 基础学习(一)context是个什么鬼

2020-11-30  本文已影响0人  六分钟热度

所谓的context,直译过来是上下文的意思。
在之前的学习中,碰到上下文的概念是在JVM运行时数据区的程序计数器中,代表线程切换时保存的数据,用以在线程切换回来时继续从之前的位置执行。

go中的context,要从三个方面说起:

1.什么是context?

context是用来控制goroutine的一种方式:在复杂goroutine应用场景中,往往需要在api边界和过程之间传递截止时间、取消信号或者其他相关的数据

goroutine是轻量级线程,用于实现go的并发编程

2.context的应用场景

goroutine的使用方式一般有三种

WaitGroup的使用方式:先往waitgroup中添加job数量,之后在不同的goroutine执行wg.Done(),在主groutine中执行wg.Wait() 等待

func CtxWaitGroup() {
    var wg sync.WaitGroup
    wg.Add(2) //在waitgroup中添加job数量
    go func() {
        time.Sleep(2 * time.Second)
        fmt.Println("老财做账")
        wg.Done() // 通知waitgroup本job完成
    }()

    go func() {
        time.Sleep(1 * time.Second)
        fmt.Println("老财审单")
        wg.Done()
    }()
    wg.Wait() //等待waitgroup中的job完成
    fmt.Println("这就是老财们的日常工作")
}

Channel的使用方式:配合select使用,希望能主动停止某个goroutine,比如某个goroutine跑太久了,我们需要发送一个信息让他停止下来,这种情况下可以使用Channel+Select的模式

// 如何主动通知停止
func CtxStopInitiative() {
    stop := make(chan bool) // 定义一个channel,传递true/false
    go func() { // 创建一个goroutine
        for {
            select {
            case <-stop: // 如果channel接收到停止请求
                fmt.Println("You are fired!")
                return
            default: // 未接收到停止请求前
                fmt.Println("老财工作中")
                time.Sleep(1 * time.Second)
            }
        }
    }()

    time.Sleep(5 * time.Second) // 等待五秒
    fmt.Println("那个老财动作太慢了!开除!")
    stop <- true // 等不下去了,向channel发送一个停止请求
    time.Sleep(5 * time.Second)
}

Context的使用方式:上面两种情况应对的是单层的goroutine调度,如果是goroutine又创建了goroutine,类似一个项目分给几个组,几个组又分别安排给组里不同的成员完成。如果我们需要某个goroutine完成时,它的子goroutine也已经完成,可以通过Context实现。

func CtxContextManyGoroutine() {
    // 父goroutine其实创建了三个子goroutine:worker;
    // 而每个worker又创建了自己的goroutine;
    // 仍然在父goroutine创建一个context对象
  // 并将其通过函数参数,分发给所有worker,当父goroutine需要停止时
  // 调用cancel()函数,所有子goroutine会接收到<-ctx.Done()结束消息,作出相应处理
    ctx, cancel := context.WithCancel(context.Background())
    go worker(ctx, "老财1")
    go worker(ctx, "老财2")
    go worker(ctx, "老财3")
    time.Sleep(1 * time.Second) // 主goroutine阻塞1秒,观察三个worker-goroutine运行情况
    fmt.Println("建立财务共享中心,老财全部优化!")
    cancel() // ctx发出了结束信号,代表主goroutine即将结束
    time.Sleep(1 * time.Second)
    fmt.Println("老财们都滚蛋了!")
}
func worker(ctx context.Context, str string) {
    go func() {
        for {
            select {
            case <-ctx.Done(): // worker-goroutine接收到结束信号,打印消息后直接返回结束
                fmt.Println(str, " 你被优化了!")
                return
            default:
                fmt.Println(str, " 工作中")
                time.Sleep(1 * time.Second)
            }
        }
    }()
}
上一篇下一篇

猜你喜欢

热点阅读