欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

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

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

目前創(chuàng)新互聯(lián)公司已為1000多家的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)絡(luò)空間、網(wǎng)站托管運營、企業(yè)網(wǎng)站設(shè)計、大城網(wǎng)站維護(hù)等服務(wù),公司將堅持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。

使用場景

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

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

看下面這個示例:

package main

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

/**
同一個content可以控制多個goroutine, 確保線程可控, 而不是每新建一個goroutine就要有一個chan去通知他關(guā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 秒過去了 \n", index)
  time.Sleep(1 * time.Second)
  if index > 10 {
   break
  }
 }

 fmt.Println("通知停止監(jiān)控")
 // 其實此時已經(jīng)超時, 協(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è)置一個時間上限, 結(jié)合 for+select 去接收消息. 當(dāng)執(zhí)行超時,或手動關(guān)閉都會給 <-ctx.Done() 發(fā)送消息,而且所有使用同一個 context 都會收到這個通知, 免去了一個一個通知的繁瑣代碼

場景二: 類似web服務(wù)器中的session

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

但是 golang 就不一樣了, 因為程序本身就能起一個 web sever, 因此就不能隨便使用全局變量了, 不然就是內(nèi)存泄露警告. 但是實際業(yè)務(wù)當(dāng)中需要有一個類似session 的東西來承載單次請求的信息, 舉一個具體的例子就是: 給每次請求加一個 uniqueID 該如何處理? 有了這個 uniqueID, 請求的所有日志都能帶上它, 這樣排查問題的時候方便追蹤一次請求發(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")
}

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

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

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

  • Gin
  • logrus

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

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

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

 Done() <-chan struct{}

 Err() error

 Value(key interface{}) interface{}
}

當(dāng)使用的時候不需要實現(xiàn)接口, 因為官方包里已經(jīng)基于 emptyCtx 實現(xiàn)了一個, 調(diào)用方法有

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

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

// 不清楚context要干嘛, 但是就得有一個ctx的用這個
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 返回一個帶 cancel 函數(shù)的ctx,
  • WithDeadline 在到達(dá)指定時間時自動執(zhí)行 cancel()
  • WithTimeout 是 WithDeadline的殼子, 區(qū)別就是這個函數(shù)是多少時間過后執(zhí)行 cancel
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
 return WithDeadline(parent, time.Now().Add(timeout))
}

WithValue 繼承父類ctx時順便帶上一個值

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。

網(wǎng)站標(biāo)題:golang通過context控制并發(fā)的應(yīng)用場景實現(xiàn)
文章分享:http://www.chinadenli.net/article34/joejpe.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供面包屑導(dǎo)航移動網(wǎng)站建設(shè)小程序開發(fā)網(wǎng)站收錄Google域名注冊

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站網(wǎng)頁設(shè)計