go 基礎(chǔ)學(xué)習(xí)(一)context是個什么鬼

所謂的context,直譯過來是上下文的意思。
在之前的學(xué)習(xí)中,碰到上下文的概念是在JVM運行時數(shù)據(jù)區(qū)的程序計數(shù)器中,代表線程切換時保存的數(shù)據(jù),用以在線程切換回來時繼續(xù)從之前的位置執(zhí)行。

go中的context,要從三個方面說起:

  • 什么是context
  • context的應(yīng)用場景
  • context源碼解讀
1.什么是context?

context是用來控制goroutine的一種方式:在復(fù)雜goroutine應(yīng)用場景中,往往需要在api邊界和過程之間傳遞截止時間、取消信號或者其他相關(guān)的數(shù)據(jù)

goroutine是輕量級線程,用于實現(xiàn)go的并發(fā)編程

2.context的應(yīng)用場景

goroutine的使用方式一般有三種

  • WaitGroup
  • Channel
  • Context

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

func CtxWaitGroup() {
    var wg sync.WaitGroup
    wg.Add(2) //在waitgroup中添加job數(shù)量
    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跑太久了,我們需要發(fā)送一個信息讓他停止下來,這種情況下可以使用Channel+Select的模式

// 如何主動通知停止
func CtxStopInitiative() {
    stop := make(chan bool) // 定義一個channel,傳遞true/false
    go func() { // 創(chuàng)建一個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發(fā)送一個停止請求
    time.Sleep(5 * time.Second)
}

Context的使用方式:上面兩種情況應(yīng)對的是單層的goroutine調(diào)度,如果是goroutine又創(chuàng)建了goroutine,類似一個項目分給幾個組,幾個組又分別安排給組里不同的成員完成。如果我們需要某個goroutine完成時,它的子goroutine也已經(jīng)完成,可以通過Context實現(xiàn)。

func CtxContextManyGoroutine() {
    // 父goroutine其實創(chuàng)建了三個子goroutine:worker;
    // 而每個worker又創(chuàng)建了自己的goroutine;
    // 仍然在父goroutine創(chuàng)建一個context對象
  // 并將其通過函數(shù)參數(shù),分發(fā)給所有worker,當(dāng)父goroutine需要停止時
  // 調(diào)用cancel()函數(shù),所有子goroutine會接收到<-ctx.Done()結(jié)束消息,作出相應(yīng)處理
    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("建立財務(wù)共享中心,老財全部優(yōu)化!")
    cancel() // ctx發(fā)出了結(jié)束信號,代表主goroutine即將結(jié)束
    time.Sleep(1 * time.Second)
    fmt.Println("老財們都滾蛋了!")
}
func worker(ctx context.Context, str string) {
    go func() {
        for {
            select {
            case <-ctx.Done(): // worker-goroutine接收到結(jié)束信號,打印消息后直接返回結(jié)束
                fmt.Println(str, " 你被優(yōu)化了!")
                return
            default:
                fmt.Println(str, " 工作中")
                time.Sleep(1 * time.Second)
            }
        }
    }()
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容