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

Go 協(xié)程超時控制的實現(xiàn)

 更新時間:2021年08月11日 15:33:54   作者:banjming  
本文主要介紹了Go 協(xié)程超時控制的實現(xiàn),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下

Go 協(xié)程超時控制

  • Select 阻塞方式
  • Context 方式

先說個場景:

假設業(yè)務中 A 服務需要調(diào)用 服務B,要求設置 5s 超時,那么如何優(yōu)雅實現(xiàn)?

Select 超時控制

考慮是否可以用 select + time.After 方式進行實現(xiàn)

這里主要利用的是通道在攜程之間通信的特點,當程序調(diào)用成功后,會向通道中發(fā)送信號。沒調(diào)用成功前,通道會阻塞。

select {
 case res := <-c2:
  fmt.Println(res)
 case <-time.After(time.Second * 3):
  fmt.Println("timeout 2")
 }

當 c2 通道中有數(shù)據(jù)時,并且超時時間沒有達到 3s,走 case res := <-c2 這個業(yè)務邏輯,當超時時間達到 3s , 走的 case <-time.After(time.Second * 3) 這個業(yè)務邏輯, 這樣就可以實現(xiàn)超時 3s 的控制。

res:= <-c2 是因為channel 可以實現(xiàn)阻塞,那么 time.After 為啥可以阻塞呢?

看 After 源碼。sleep.go 可以看到其實也是 channel

func After(d Duration) <-chan Time {
 return NewTimer(d).C
}

完整代碼示例:

package timeout

import (
 "fmt"
 "testing"
 "time"
)

func TestSelectTimeOut(t *testing.T) {
 // 在這個例子中, 假設我們執(zhí)行了一個外部調(diào)用, 2秒之后將結(jié)果寫入c1
 c1 := make(chan string, 1)
 go func() {
  time.Sleep(time.Second * 2)
  c1 <- "result 1"
 }()
 // 這里使用select來實現(xiàn)超時, `res := <-c1`等待通道結(jié)果,
 // `<- Time.After`則在等待1秒后返回一個值, 因為select首先
 // 執(zhí)行那些不再阻塞的case, 所以這里會執(zhí)行超時程序, 如果
 // `res := <-c1`超過1秒沒有執(zhí)行的話
 select {
 case res := <-c1:
  fmt.Println(res)
 case <-time.After(time.Second * 1):
  fmt.Println("timeout 1")
 }
 // 如果我們將超時時間設為3秒, 這個時候`res := <-c2`將在
 // 超時case之前執(zhí)行, 從而能夠輸出寫入通道c2的值
 c2 := make(chan string, 1)
 go func() {
  time.Sleep(time.Second * 2)
  c2 <- "result 2"
 }()
 select {
 case res := <-c2:
  fmt.Println(res)
 case <-time.After(time.Second * 3):
  fmt.Println("timeout 2")
 }
}

運行結(jié)果:

=== RUN   TestSelectTimeOut
timeout 1
result 2
--- PASS: TestSelectTimeOut (3.00s)
PASS

go timer 計時器

這個是 timer 類似的計時器實現(xiàn),通用也是通過通道來發(fā)送數(shù)據(jù)。

package main
import "time"
import "fmt"
func main() {
  // Ticker使用和Timer相似的機制, 同樣是使用一個通道來發(fā)送數(shù)據(jù)。
  // 這里我們使用range函數(shù)來遍歷通道數(shù)據(jù), 這些數(shù)據(jù)每隔500毫秒被
  // 發(fā)送一次, 這樣我們就可以接收到
  ticker := time.NewTicker(time.Millisecond * 500)
  go func() {
    for t := range ticker.C {
    fmt.Println("Tick at", t)
    }
  }()
  // Ticker和Timer一樣可以被停止。 一旦Ticker停止后, 通道將不再
  // 接收數(shù)據(jù), 這里我們將在1500毫秒之后停止
  time.Sleep(time.Millisecond * 1500)
  ticker.Stop()
  fmt.Println("Ticker stopped")
}

go context

context 監(jiān)聽是否有 IO 操作,開始從當前連接中讀取網(wǎng)絡請求,每當讀取到一個請求則會將該cancelCtx傳入,用以傳遞取消信號,可發(fā)送取消信號,取消所有進行中的網(wǎng)絡請求。

  go func(ctx context.Context, info *Info) {
   timeLimit := 120
   timeoutCtx, cancel := context.WithTimeout(ctx, time.Duration(timeLimit)*time.Millisecond)
   defer func() {
    cancel()
    wg.Done()
   }()
   resp := DoHttp(timeoutCtx, info.req)
  }(ctx, info)

關鍵看業(yè)務代碼: resp := DoHttp(timeoutCtx, info.req) 業(yè)務代碼中包含 http 調(diào)用 NewRequestWithContext

req, err := http.NewRequestWithContext(ctx, "POST", url, strings.NewReader(paramString))

上面的代碼,設置了過期時間,當DoHttp(timeoutCtx, info.req) 處理時間超過超時時間時,會自動截止,并且打印 context deadline exceeded。

看個代碼:

package main

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

func TestTimerContext(t *testing.T) {
 now := time.Now()
 later, _ := time.ParseDuration("10s")

 ctx, cancel := context.WithDeadline(context.Background(), now.Add(later))
 defer cancel()
 go Monitor(ctx)

 time.Sleep(20 * time.Second)

}

func Monitor(ctx context.Context) {
 select {
 case <-ctx.Done():
  fmt.Println(ctx.Err())
 case <-time.After(20 * time.Second):
  fmt.Println("stop monitor")
 }
}

運行結(jié)果:

=== RUN   TestTimerContext
context deadline exceeded
--- PASS: TestTimerContext (20.00s)
PASS

Context 接口有如下:

type Context interface {
    Deadline() (deadline time.Time, ok bool)
    Done() <-chan struct{}
    Err() error
    Value(key interface{}) interface{}
}
  • Deadline — 返回 context.Context 被取消的時間,也就是完成工作的截止日期;
  • Done — 返回一個 Channel,這個 Channel 會在當前工作完成或者上下文被取消之后關閉,多次調(diào)用 Done 方法會返回同一個 Channel;
  • Err — 返回 context.Context 結(jié)束的原因,它只會在 Done 返回的 Channel 被關閉時才會返回非空的值;
    • 如果 context.Context 被取消,會返回 Canceled 錯誤;
    • 如果 context.Context 超時,會返回 DeadlineExceeded 錯誤;
  • Value — 從 context.Context 中獲取鍵對應的值,對于同一個上下文來說,多次調(diào)用 Value 并傳入相同的 Key 會返回相同的結(jié)果,該方法可以用來傳遞請求特定的數(shù)據(jù);

到此這篇關于Go 協(xié)程超時控制的實現(xiàn)的文章就介紹到這了,更多相關Go 協(xié)程超時控制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 用gin開發(fā)的golang項目三種開發(fā)模式方式

    用gin開發(fā)的golang項目三種開發(fā)模式方式

    這篇文章主要介紹了用gin開發(fā)的golang項目三種開發(fā)模式方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • Go?一般方法與接口方法接收者的差異詳解

    Go?一般方法與接口方法接收者的差異詳解

    這篇文章主要為大家介紹了Go?一般方法與接口方法接收者的差異詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-05-05
  • 詳解go中的defer鏈如何被遍歷執(zhí)行

    詳解go中的defer鏈如何被遍歷執(zhí)行

    為了在退出函數(shù)前執(zhí)行一些資源清理的操作,例如關閉文件、釋放連接、釋放鎖資源等,會在函數(shù)里寫上多個defer語句,多個_defer 結(jié)構體形成一個鏈表,G 結(jié)構體中某個字段指向此鏈表,那么go中的defer鏈如何被遍歷執(zhí)行,本文將給大家詳細的介紹,感興趣的朋友可以參考下
    2024-01-01
  • 解析Golang中的鎖競爭問題

    解析Golang中的鎖競爭問題

    這篇文章主要介紹了golang中的鎖競爭問題,本文通過實例代碼給大家詳細講解,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-10-10
  • Golang二維數(shù)組的使用方式

    Golang二維數(shù)組的使用方式

    之前給大家講過很多二維數(shù)組的知識,今天重點給大家介紹Golang二維數(shù)組的使用方式,通過示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2021-05-05
  • Go語言官方依賴注入工具Wire的使用教程

    Go語言官方依賴注入工具Wire的使用教程

    依賴注入是一種實現(xiàn)控制反轉(zhuǎn)且用于解決依賴性問題的設計模式。Golang?中常用的依賴注入工具主要有?Inject?、Dig?等。但是今天主要介紹的是?Go?團隊開發(fā)的?Wire,一個編譯期實現(xiàn)依賴注入的工具,感興趣的可以了解一下
    2022-09-09
  • Go語言 go程釋放操作(退出/銷毀)

    Go語言 go程釋放操作(退出/銷毀)

    這篇文章主要介紹了Go語言 go程釋放操作(退出/銷毀),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • golang關閉chan通道的方法示例

    golang關閉chan通道的方法示例

    在go語言中,通道(channel)是一個非常重要的概念,通道提供了一種在不同 goroutine 之間安全地傳遞數(shù)據(jù)的方式,在本文中,我們將討論如何關閉通道以及在關閉通道時需要考慮的事項,需要的朋友可以參考下
    2024-02-02
  • golang高并發(fā)的深入理解

    golang高并發(fā)的深入理解

    golang從語言級別上對并發(fā)提供了支持,而且在啟動并發(fā)的方式上直接添加了語言級的關鍵字。下面這篇文章主要給大家介紹了關于golang高并發(fā)的相關資料,需要的朋友可以參考下
    2019-03-03
  • Golang學習筆記(六):struct

    Golang學習筆記(六):struct

    這篇文章主要介紹了Golang學習筆記(六):struct,本文講解了struct的聲明及初始化、struct的匿名字段(繼承)、method、method繼承和重寫等內(nèi)容,需要的朋友可以參考下
    2015-05-05

最新評論

始兴县| 台中县| 永吉县| 家居| 广宗县| 阜新| 新余市| 高邮市| 黄冈市| 昭平县| 宁晋县| 河西区| 法库县| 法库县| 油尖旺区| 儋州市| 宝山区| 屯留县| 宜宾县| 罗山县| 瓦房店市| 吕梁市| 红河县| 凤城市| 聂拉木县| 炉霍县| 荔波县| 宜都市| 正安县| 南阳市| 巴林右旗| 潞城市| 剑阁县| 长武县| 大冶市| 阿巴嘎旗| 治多县| 洪泽县| 靖安县| 泗阳县| 平山县|