最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

golang通過(guò)context控制并發(fā)的應(yīng)用場(chǎng)景實(shí)現(xiàn)

 更新時(shí)間:2020年01月07日 15:18:04   作者:只是一個(gè)id  
這篇文章主要介紹了golang通過(guò)context控制并發(fā)的應(yīng)用場(chǎng)景實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

golang 里出現(xiàn)多 goroutine 的場(chǎng)景很常見(jiàn), 最常用的兩種方式就是 WaitGroup 和 Context, 今天我們了解一下 Context 的應(yīng)用場(chǎng)景

使用場(chǎng)景

場(chǎng)景一: 多goroutine執(zhí)行超時(shí)通知

并發(fā)執(zhí)行的業(yè)務(wù)中最常見(jiàn)的就是有協(xié)程執(zhí)行超時(shí), 如果不做超時(shí)處理就會(huì)出現(xiàn)一個(gè)僵尸進(jìn)程, 這累計(jì)的多了就會(huì)有一陣手忙腳亂了, 所以我們要在源頭上就避免它們

看下面這個(gè)示例:

package main

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

/**
同一個(gè)content可以控制多個(gè)goroutine, 確保線程可控, 而不是每新建一個(gè)goroutine就要有一個(gè)chan去通知他關(guān)閉
有了他代碼更加簡(jiǎn)潔
*/

func main() {
 fmt.Println("run demo \n\n\n")
 demo()
}

func demo() {
 ctx, cancel := context.WithTimeout(context.Background(), 9*time.Second)
 go watch(ctx, "[線程1]")
 go watch(ctx, "[線程2]")
 go watch(ctx, "[線程3]")

 index := 0
 for {
  index++
  fmt.Printf("%d 秒過(guò)去了 \n", index)
  time.Sleep(1 * time.Second)
  if index > 10 {
   break
  }
 }

 fmt.Println("通知停止監(jiān)控")
 // 其實(shí)此時(shí)已經(jīng)超時(shí), 協(xié)程已經(jīng)提前退出
 cancel()

 // 防止主進(jìn)程提前退出
 time.Sleep(3 * time.Second)
 fmt.Println("done")
}

func watch(ctx context.Context, name string) {
 for {
  select {
  case <-ctx.Done():
   fmt.Printf("%s 監(jiān)控退出, 停止了...\n", name)
   return
  default:
   fmt.Printf("%s goroutine監(jiān)控中... \n", name)
   time.Sleep(2 * time.Second)
  }
 }
}

使用 context.WithTimeout() 給文本流設(shè)置一個(gè)時(shí)間上限, 結(jié)合 for+select 去接收消息. 當(dāng)執(zhí)行超時(shí),或手動(dòng)關(guān)閉都會(huì)給 <-ctx.Done() 發(fā)送消息,而且所有使用同一個(gè) context 都會(huì)收到這個(gè)通知, 免去了一個(gè)一個(gè)通知的繁瑣代碼

場(chǎng)景二: 類(lèi)似web服務(wù)器中的session

比如在php中(沒(méi)用swoole擴(kuò)展), 一個(gè)請(qǐng)求進(jìn)來(lái), 從 $_REQUEST $_SERVER 能獲取到的是有關(guān)這一條請(qǐng)求的所有信息, 哪怕是使用全局變量也是給這一個(gè)請(qǐng)求來(lái)服務(wù)的, 是線程安全的

但是 golang 就不一樣了, 因?yàn)槌绦虮旧砭湍芷鹨粋€(gè) web sever, 因此就不能隨便使用全局變量了, 不然就是內(nèi)存泄露警告. 但是實(shí)際業(yè)務(wù)當(dāng)中需要有一個(gè)類(lèi)似session 的東西來(lái)承載單次請(qǐng)求的信息, 舉一個(gè)具體的例子就是: 給每次請(qǐng)求加一個(gè) uniqueID 該如何處理? 有了這個(gè) uniqueID, 請(qǐng)求的所有日志都能帶上它, 這樣排查問(wèn)題的時(shí)候方便追蹤一次請(qǐng)求發(fā)生了什么

如下:

func demo2() {
 pCtx, pCancel := context.WithCancel(context.Background())
 pCtx = context.WithValue(pCtx, "parentKey", "parentVale")
 go watch(pCtx, "[父進(jìn)程1]")
 go watch(pCtx, "[父進(jìn)程2]")

 cCtx, cCancel := context.WithCancel(pCtx)
 go watch(cCtx, "[子進(jìn)程1]")
 go watch(cCtx, "[子進(jìn)程2]")
 fmt.Println(pCtx.Value("parentKey"))
 fmt.Println(cCtx.Value("parentKey"))

 time.Sleep(10 * time.Second)
 fmt.Println("子進(jìn)程關(guān)閉")
 cCancel()
 time.Sleep(5 * time.Second)
 fmt.Println("父進(jìn)程關(guān)閉")
 pCancel()

 time.Sleep(3 * time.Second)
 fmt.Println("done")
}

最開(kāi)始的 context.WithCancel(context.Background()) 中 context.Background() 就是一個(gè)新建的 context, 利用 context 能繼承的特性, 可以將自己的程序構(gòu)建出一個(gè) context 樹(shù), context 執(zhí)行 cancel() 將影響到當(dāng)前 context 和子 context, 不會(huì)影響到父級(jí).

同時(shí) context.WithValue 也會(huì)給 context 帶上自定義的值, 這樣 uniqueID 就能輕松的傳遞了下去, 而不是一層層的傳遞參數(shù), 改func什么的

對(duì)于 context 很值得參考的應(yīng)用有:

Context 相關(guān) func 和接口

繼承 context 需要實(shí)現(xiàn)如下四個(gè)接口

type Context interface {
 Deadline() (deadline time.Time, ok bool)

 Done() <-chan struct{}

 Err() error

 Value(key interface{}) interface{}
}

當(dāng)使用的時(shí)候不需要實(shí)現(xiàn)接口, 因?yàn)楣俜桨镆呀?jīng)基于 emptyCtx 實(shí)現(xiàn)了一個(gè), 調(diào)用方法有

var (
 background = new(emptyCtx)
 todo  = new(emptyCtx)
)

// 這個(gè)是最初始的ctx, 之后的子ctx都是繼承自它
func Background() Context {
 return background
}

// 不清楚context要干嘛, 但是就得有一個(gè)ctx的用這個(gè)
func TODO() Context {
 return todo
}

繼承用的函數(shù)

func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
func WithValue(parent Context, key, val interface{}) Context
  • WithCancel 返回一個(gè)帶 cancel 函數(shù)的ctx,
  • WithDeadline 在到達(dá)指定時(shí)間時(shí)自動(dòng)執(zhí)行 cancel()
  • WithTimeout 是 WithDeadline的殼子, 區(qū)別就是這個(gè)函數(shù)是多少時(shí)間過(guò)后執(zhí)行 cancel
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
 return WithDeadline(parent, time.Now().Add(timeout))
}

WithValue 繼承父類(lèi)ctx時(shí)順便帶上一個(gè)值

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Golang程序中使用Prometheus的client_golang庫(kù)

    Golang程序中使用Prometheus的client_golang庫(kù)

    這篇文章主要介紹了Golang程序中使用Prometheus的client_golang庫(kù),Prometheus 是一個(gè)開(kāi)源的監(jiān)控和警報(bào)工具包,用于收集和處理應(yīng)用程序和系統(tǒng)的指標(biāo)數(shù)據(jù)。Prometheus 提供了多種客戶端庫(kù),可以輕松地集成到各種編程語(yǔ)言中
    2023-04-04
  • 使用Go語(yǔ)言創(chuàng)建WebSocket服務(wù)的實(shí)現(xiàn)示例

    使用Go語(yǔ)言創(chuàng)建WebSocket服務(wù)的實(shí)現(xiàn)示例

    這篇文章主要介紹了使用Go語(yǔ)言創(chuàng)建WebSocket服務(wù)的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03
  • go語(yǔ)言題解LeetCode1128等價(jià)多米諾骨牌對(duì)的數(shù)量

    go語(yǔ)言題解LeetCode1128等價(jià)多米諾骨牌對(duì)的數(shù)量

    這篇文章主要為大家介紹了go語(yǔ)言題解LeetCode1128等價(jià)多米諾骨牌對(duì)的數(shù)量示例詳解,
    2022-12-12
  • uber go zap 日志框架支持異步日志輸出

    uber go zap 日志框架支持異步日志輸出

    這篇文章主要為大家介紹了uber go zap 日志框架支持異步日志輸出示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • Go可變參數(shù)函數(shù)的實(shí)現(xiàn)

    Go可變參數(shù)函數(shù)的實(shí)現(xiàn)

    可變參數(shù)函數(shù)是指函數(shù)參數(shù)的某個(gè)參數(shù)可有可無(wú),即這個(gè)參數(shù)的個(gè)數(shù)可以為0會(huì)多個(gè),可變參數(shù)函數(shù)參數(shù)在日常編程中大量使用,本文主要介紹了Go可變參數(shù)函數(shù)的實(shí)現(xiàn),感興趣的可以了解一下
    2023-12-12
  • 一文教你Golang如何正確關(guān)閉通道

    一文教你Golang如何正確關(guān)閉通道

    Go在通道這一塊,沒(méi)有內(nèi)置函數(shù)判斷通道是否已經(jīng)關(guān)閉,也沒(méi)有可以直接獲取當(dāng)前通道數(shù)量的方法,因此如果對(duì)通道進(jìn)行了錯(cuò)誤的使用,將會(huì)直接引發(fā)系統(tǒng)?panic,這是一件很危險(xiǎn)的事情,下面我們就來(lái)學(xué)習(xí)一下如何正確關(guān)閉通道吧
    2023-10-10
  • golang中"var"與":="的區(qū)別解析

    golang中"var"與":="的區(qū)別解析

    這篇文章主要介紹了golang中“var”與“:=”的區(qū)別,使用var關(guān)鍵字是Go最基本的定義變量方式,有時(shí)也會(huì)使用到:=來(lái)定義變量,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-04-04
  • 一百行Golang代碼實(shí)現(xiàn)簡(jiǎn)單并發(fā)聊天室

    一百行Golang代碼實(shí)現(xiàn)簡(jiǎn)單并發(fā)聊天室

    這篇文章主要為大家詳細(xì)介紹了一百行Golang代碼如何實(shí)現(xiàn)簡(jiǎn)單并發(fā)聊天室,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • 淺談Go 語(yǔ)言中逃逸分析是怎么進(jìn)行的

    淺談Go 語(yǔ)言中逃逸分析是怎么進(jìn)行的

    Go 語(yǔ)言的逃逸分析是在編譯階段進(jìn)行的靜態(tài)分析過(guò)程,用于確定變量的內(nèi)存分配位置,本文就來(lái)介紹一下逃逸分析是怎么進(jìn)行的,具有一定的參考價(jià)值,感興趣的可以了解一下
    2025-10-10
  • golang通過(guò)遞歸遍歷生成樹(shù)狀結(jié)構(gòu)的操作

    golang通過(guò)遞歸遍歷生成樹(shù)狀結(jié)構(gòu)的操作

    這篇文章主要介紹了golang通過(guò)遞歸遍歷生成樹(shù)狀結(jié)構(gòu)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-04-04

最新評(píng)論

德江县| 盐亭县| 阜新市| 大渡口区| 竹溪县| 博兴县| 凭祥市| 马山县| 砀山县| 承德市| 平乐县| 星座| 崇礼县| 三台县| 定兴县| 太湖县| 东丽区| 翼城县| 郴州市| 尼玛县| 盐池县| 科技| 西畴县| 大渡口区| 临清市| 花垣县| 波密县| 葵青区| 民县| 南投县| 汝州市| 平远县| 类乌齐县| 宾阳县| 赞皇县| 富宁县| 鄄城县| 比如县| 克东县| 上蔡县| 治多县|