Go Context上下文的應(yīng)用

Go的上下文應(yīng)用

1.背景原理

Go上下文就是context。對于go來說go routine(協(xié)程)是一個非常有用的方法。
本來用chan(通道)也可以達到控制的目的,無奈如果開的協(xié)程太多的話,控制起來就很麻煩。光命名都頭疼。
后來又有了sync.WaitGroup來控制,不過好像也沒有那么優(yōu)雅。沒有怎么研究。
context(上下文)的出現(xiàn),優(yōu)雅的解決了這個問題。
context的原理:


clipboard.png
2.png

context可以創(chuàng)建父子結(jié)構(gòu),樹形結(jié)構(gòu),如上圖。

2.舉例說明

設(shè)定一個需求:
需要建立一組協(xié)程,協(xié)程圖如下:

main-->A1(協(xié)程)-->A1_1(協(xié)程)->A1_1_1(協(xié)程)
|->B(協(xié)程)->B1(協(xié)程)
A1熔斷時間:5s; A_1熔斷時間:4s; A_1_1熔斷時間:3s
B1錯誤,全部結(jié)束

上源碼:

package main

import (
    "context"
    "fmt"
    "log"
    "time"
)

func main() {
    contextNodeMain()
}

/*
需求概述
主程序的協(xié)程
main->A->A_1->A_1_1
   |->B->B1
   主程序的斷熔時間為5s;A為4s;A_1為3.5s;A_1_1為3S;
   若B1錯誤,主程序強制結(jié)束
*/
func contextNodeMain() {
    d := time.Now().Add(5000 * time.Millisecond)
    ctx, cancel := context.WithDeadline(context.Background(), d)
    defer func() { cancel() }()
    //B1結(jié)束通道
    ch := make(chan bool)
    go A(ctx)
    go B(ctx, ch)

    select {
    case <-ctx.Done(): //全部聲明周期燃盡
        log.Println("所有協(xié)程關(guān)閉") 
    case <-ch: //B1發(fā)生錯誤全部結(jié)束
        log.Println("發(fā)生錯誤,其余協(xié)程結(jié)束")
        return
        //cancel()
    }

}
func B(ctx context.Context, ch chan bool) {
    log.Println("B 開始工作")
    B_1(ch)
}

func B_1(ch chan bool) {
    time.Sleep(time.Second * 10)
    log.Println("B_1 發(fā)生錯誤")
    ch <- false
}

func A(ctx context.Context) {
    ctx_A, cancel := context.WithTimeout(ctx, time.Millisecond*time.Duration(4000)) //A_1執(zhí)行時間為3.5秒
    log.Println("A 開始工作")
    defer cancel()
    go A_1(ctx_A)
    for {
        select {
        case <-ctx.Done():
            log.Println("A停止工作")
            return
            // case <-time.After(time.Second):
            //  log.Println("A wroking")
        }
    }

}
func A_1(ctx context.Context) {
    ctx_A_1, cancel := context.WithTimeout(ctx, time.Millisecond*time.Duration(3000)) //A_1_1的執(zhí)行時間為3秒
    log.Println("A_1 開始工作")
    defer cancel()
    go A_1_1(ctx_A_1)
    for {
        select {
        case <-ctx.Done():
            log.Println("A_1停止工作")
            return
        }
    }
}
func A_1_1(ctx context.Context) {
    log.Println("A_1_1 開始工作")
    for {
        select {
        case <-ctx.Done():
            log.Println("A_1_1停止工作")
            return

        }
    }
}
QQ截圖20191106100353.png

從結(jié)果中我們可以看到
1.10s時,A和B都開始工作。
2.在13秒的時候,A_1_1停止工作,正好是3S。
3.在14s的時候,A_1停止工作,差4s
4.在15S的時候,協(xié)程關(guān)閉,差5s

也就是按照我們設(shè)想的,停止順序為A_1_1->A_1->A

如果B_1發(fā)生錯誤,我們只需要改一下B,模擬B_1發(fā)生錯誤修改代碼如下

func B_1(ch chan bool) {
    time.Sleep(time.Second * 3)
    log.Println("B_1 發(fā)生錯誤")
    ch <- false
}

結(jié)果如下:


QQ截圖20191106101013.png

如果B_1發(fā)生錯誤,協(xié)程全部關(guān)閉。

?著作權(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)容

  • 專業(yè)考題類型管理運行工作負(fù)責(zé)人一般作業(yè)考題內(nèi)容選項A選項B選項C選項D選項E選項F正確答案 變電單選GYSZ本規(guī)程...
    小白兔去釣魚閱讀 10,488評論 0 13
  • 一、Context概述 1.緣起 在開發(fā)web服務(wù)應(yīng)用時,我們知道http啟動的服務(wù)每接收到一個請求是便啟動一個g...
    GoFuncChan閱讀 1,338評論 0 0
  • 選擇題部分 1.(),只有在發(fā)生短路事故時或者在負(fù)荷電流較大時,變流器中才會有足夠的二次電流作為繼電保護跳閘之用。...
    skystarwuwei閱讀 14,361評論 0 7
  • ¥開啟¥ 【iAPP實現(xiàn)進入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個線程,因...
    小菜c閱讀 7,311評論 0 17
  • 引言 context 是 Go 中廣泛使用的程序包,由 Google 官方開發(fā),在 1.7 版本引入。它用來簡化在...
    51reboot閱讀 3,628評論 0 10

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