亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Golang > 正文

Go并發調用的超時處理的方法

2020-04-01 18:50:20
字體:
來源:轉載
供稿:網友

之前有聊過 golang 的協程,我發覺似乎還很理論,特別是在并發安全上,所以特結合網上的一些例子,來試驗下go routine中 的 channel, select, context 的妙用。

場景-微服務調用

我們用 gin(一個web框架) 作為處理請求的工具,需求是這樣的:

一個請求 X 會去并行調用 A, B, C 三個方法,并把三個方法返回的結果加起來作為 X 請求的 Response。

但是我們這個 Response 是有時間要求的(不能超過3秒的響應時間),可能 A, B, C 中任意一個或兩個,處理邏輯十分復雜,或者數據量超大,導致處理時間超出預期,那么我們就馬上切斷,并返回已經拿到的任意個返回結果之和。

我們先來定義主函數:

func main() { r := gin.New() r.GET("/calculate", calHandler) http.ListenAndServe(":8008", r)}

非常簡單,普通的請求接受和 handler 定義。其中 calHandler 是我們用來處理請求的函數。

分別定義三個假的微服務,其中第三個將會是我們超時的哪位~

func microService1() int { time.Sleep(1*time.Second) return 1}func microService2() int { time.Sleep(2*time.Second) return 2}func microService3() int { time.Sleep(10*time.Second) return 3}

接下來,我們看看 calHandler 里到底是什么

func calHandler(c *gin.Context) { ...}

要點1--并發調用

直接用 go 就好了嘛~

所以一開始我們可能就這么寫:

go microService1()go microService2()go microService3()

很簡單有沒有,但是等等,說好的返回值我怎么接呢?

為了能夠并行地接受處理結果,我們很容易想到用 channel 去接。

所以我們把調用服務改成這樣:

var resChan = make(chan int, 3) // 因為有3個結果,所以我們創建一個可以容納3個值的 int channel。go func() { resChan <- microService1()}()go func() { resChan <- microService2()}()go func() { resChan <- microService3()}()

有東西接,那也要有方法去算,所以我們加一個一直循環拿 resChan 中結果并計算的方法:

var resContainer, sum intfor { resContainer = <-resChan sum += resContainer}

這樣一來我們就有一個 sum 來計算每次從 resChan 中拿出的結果了。

要點2--超時信號

還沒結束,說好的超時處理呢?

為了實現超時處理,我們需要引入一個東西,就是 context,什么是 context ?

我們這里只使用 context 的一個特性,超時通知(其實這個特性完全可以用 channel 來替代)。

可以看在定義 calHandler 的時候我們已經將 c *gin.Context 作為參數傳了進來,那我們就不用自己在聲明了。
gin.Context 簡單理解為貫穿整個 gin 聲明周期的上下文容器,有點像是分身,亦或是量子糾纏的感覺。

有了這個 gin.Context, 我們就能在一個地方對 context 做出操作,而其他正在使用 context 的函數或方法,也會感受到 context 做出的變化。

ctx, _ := context.WithTimeout(c, 3*time.Second) //定義一個超時的 context

只要時間到了,我們就能用 ctx.Done() 獲取到一個超時的 channel(通知),然后其他用到這個 ctx 的地方也會停掉,并釋放 ctx。

一般來說,ctx.Done() 是結合 select 使用的。

所以我們又需要一個循環來監聽 ctx.Done()

for { select { case <- ctx.Done():  // 返回結果}

現在我們有兩個 for 了,是不是能夠合并下?

for { select { case resContainer = <-resChan:  sum += resContainer  fmt.Println("add", resContainer) case <- ctx.Done():  fmt.Println("result:", sum)  return }}

誒嘿,看上去不錯。

不過我們怎么在正常完成微服務調用的時候輸出結果呢?

看來我們還需要一個 flag

var count intfor { select { case resContainer = <-resChan:  sum += resContainer  count ++  fmt.Println("add", resContainer)  if count > 2 {   fmt.Println("result:", sum)   return  } case <- ctx.Done():  fmt.Println("timeout result:", sum)  return }}

我們加入一個計數器,因為我們只是調用3次微服務,所以當 count 大于2的時候,我們就應該結束并輸出結果了。

要點3--并發中的等待

上面的計時器是一種偷懶的方法,因為我們知道了調用微服務的次數,如果我們并不知道,或者之后還要添加呢?
手動每次改 count 的判斷閾值會不會太沙雕了?這時候我們就要加入 sync 包了。
我們將會使用的 sync 的一個特性是 WaitGroup。它的作用是等待一組協程運行完畢后,執行接下去的步驟。

我們來改下之前微服務調用的代碼塊:

var success = make(chan int, 1) // 成功的通道標識wg := sync.WaitGroup{} // 創建一個 waitGroup 組wg.Add(3) // 我們往組里加3個標識,因為我們要運行3個任務go func() { resChan <- microService1() wg.Done() // 完成一個,Done()一個}()go func() { resChan <- microService2() wg.Done()}()go func() { resChan <- microService3() wg.Done()}()wg.Wait() // 直到我們前面三個標識都被 Done 了,否則程序一直會阻塞在這里success <- 1 // 我們發送一個成功信號到通道中

既然我們有了 success 這個信號,那么再把它加入到監控 for 循環中,并做些修改,刪除原來 count 判斷的部分。

go func() { for {  select {  case resContainer = <-resChan:   sum += resContainer   fmt.Println("add", resContainer)  case <- success:   fmt.Println("result:", sum)   return  case <- ctx.Done():   fmt.Println("result:", sum)   return  } }}()

三個 case,分工明確,一個用來拿服務輸出的結果并計算,一個用來做最終的完成輸出,一個是超時輸出。
同時我們將這個循環監聽,也作為協程運行。

至此,所有的主要代碼都完成了。下面是完全版

package mainimport ( "context" "fmt" "net/http" "sync" "time" "github.com/gin-gonic/gin")// 一個請求會觸發調用三個服務,每個服務輸出一個 int,// 請求要求結果為三個服務輸出 int 之和// 請求返回時間不超過3秒,大于3秒只輸出已經獲得的 int 之和func calHandler(c *gin.Context) { var resContainer, sum int var success, resChan = make(chan int), make(chan int, 3) ctx, _ := context.WithTimeout(c, 3*time.Second) go func() {  for {   select {   case resContainer = <-resChan:    sum += resContainer    fmt.Println("add", resContainer)   case <- success:    fmt.Println("result:", sum)    return   case <- ctx.Done():    fmt.Println("result:", sum)    return   }  } }() wg := sync.WaitGroup{} wg.Add(3) go func() {  resChan <- microService1()  wg.Done() }() go func() {  resChan <- microService2()  wg.Done() }() go func() {  resChan <- microService3()  wg.Done() }() wg.Wait() success <- 1 return}func main() { r := gin.New() r.GET("/calculate", calHandler) http.ListenAndServe(":8008", r)}func microService1() int { time.Sleep(1*time.Second) return 1}func microService2() int { time.Sleep(2*time.Second) return 2}func microService3() int { time.Sleep(10*time.Second) return 3}

上面的程序只是簡單描述了一個調用其他微服務超時的處理場景。

實際過程中還需要加很多很多調料,才能保證接口的對外完整性。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
97视频在线看| 欧美日韩午夜视频在线观看| 久久久亚洲国产| 欧美日韩亚洲激情| 亚洲国产一区二区三区四区| 欧美精品亚州精品| 日韩视频免费大全中文字幕| 国产成人精品在线| 亚洲视频一区二区| 色婷婷综合久久久久中文字幕1| 美日韩精品免费观看视频| 久久精品国亚洲| 96pao国产成视频永久免费| 国产精品网站大全| 亚洲2020天天堂在线观看| 国产免费观看久久黄| 亚洲欧美视频在线| 国产噜噜噜噜噜久久久久久久久| 成人国产精品日本在线| 欧美日韩免费观看中文| 美女视频久久黄| 国产精品电影网| 欧美激情精品久久久久久久变态| 日韩亚洲欧美中文在线| 最新国产精品拍自在线播放| 欧美午夜精品久久久久久人妖| 亚洲国产成人爱av在线播放| 亚洲成人av在线播放| 欧美日韩在线一区| 亚洲视频在线观看免费| 91成人精品网站| 欧美激情视频给我| 国产精品久久久久久久美男| 国产成人jvid在线播放| 欧美综合激情网| 久久久久久国产精品三级玉女聊斋| 国产精品v片在线观看不卡| 亚洲视频在线观看网站| 成人黄色av网站| 日韩av在线资源| 久久精品美女视频网站| 7777免费精品视频| 欧美精品在线第一页| 亚洲精品按摩视频| 国产视频久久网| 欧美电影免费观看网站| 91精品国产电影| 爽爽爽爽爽爽爽成人免费观看| 欧美激情国产高清| 国产精品视频久久| 国产精品视频yy9099| 日韩中文字在线| 国产精品美女网站| 亚洲色无码播放| 91免费综合在线| 全色精品综合影院| 精品香蕉在线观看视频一| 色妞久久福利网| 日韩美女激情视频| 日本精品性网站在线观看| 国产精品一区二区三| 人体精品一二三区| 日本欧美一二三区| 国产精品视频99| 久久夜精品va视频免费观看| 国产精品久久久久久久久免费| 一本色道久久综合狠狠躁篇怎么玩| 韩曰欧美视频免费观看| 国产亚洲精品高潮| 亚洲xxx自由成熟| 自拍偷拍亚洲精品| 国产精品久久久久久五月尺| 欧美国产极速在线| 亚洲福利视频网| 欧美日韩亚洲一区二区三区| 亚洲日本中文字幕免费在线不卡| 日韩hd视频在线观看| 欧美精品日韩三级| 精品一区二区三区三区| 亚洲午夜女主播在线直播| 国产精品欧美一区二区三区奶水| 久久亚洲国产精品成人av秋霞| 国产经典一区二区| 在线视频日韩精品| 欧美激情精品久久久久久大尺度| 欧美专区在线观看| 日韩国产精品一区| 亚洲成人av资源网| 精品动漫一区二区| 国产亚洲精品日韩| 亚洲性视频网址| 国内精品一区二区三区四区| 亚洲va国产va天堂va久久| 亚洲国产精彩中文乱码av| 亚洲精品美女在线观看| 九九热在线精品视频| 欧美孕妇与黑人孕交| 亚洲精品福利视频| 欧美成人午夜激情视频| 日韩在线免费视频| 国产精品三级久久久久久电影| 日韩国产高清污视频在线观看| 在线国产精品播放| 久久人人爽人人| 欧美精品在线播放| 俺去亚洲欧洲欧美日韩| 久久精品国亚洲| 久久久精品一区| 国产精品 欧美在线| 久久精品视频中文字幕| 亚洲欧美激情另类校园| 久久久精品免费| 国产一区二区在线免费| 亚洲深夜福利视频| 久久九九全国免费精品观看| 亚洲日韩第一页| 国产精品无av码在线观看| 国产精品欧美一区二区| 欧美一区二区三区免费视| 欧美视频免费在线| 亚洲欧美日韩成人| 亚洲女人天堂成人av在线| 国产在线观看精品| 欧美激情视频播放| 日本精品视频在线观看| 久久精品99久久香蕉国产色戒| 日韩av在线不卡| 亚洲国产高清高潮精品美女| 久久精品这里热有精品| 国产日韩欧美在线观看| 中文字幕欧美亚洲| 国产v综合v亚洲欧美久久| 欧美日韩精品国产| 亚洲国模精品私拍| 成人午夜激情网| 亚洲v日韩v综合v精品v| 国产一区二区欧美日韩| 国产精品女主播视频| 精品亚洲一区二区三区| 久久久精品国产| 亚洲美女免费精品视频在线观看| 国产91露脸中文字幕在线| 国产精品视频不卡| 亚洲天堂av在线播放| 日韩毛片中文字幕| 国产不卡av在线免费观看| 久久中文字幕在线视频| 久久久在线免费观看| 欧美黄色片免费观看| 国产精品电影观看| 日韩av影院在线观看| 国产亚洲精品一区二555| 日韩免费高清在线观看| 黄网站色欧美视频| 亚洲新声在线观看| 日韩最新av在线| 亚洲国产欧美一区| 欧美日本亚洲视频| 国产精品白丝av嫩草影院| 久久亚洲精品一区| 欧美极品少妇xxxxⅹ免费视频| 久久亚洲精品视频| 欧美精品精品精品精品免费| 91欧美精品成人综合在线观看|