91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Go怎么實現協程超時控制

發布時間:2021-08-12 09:27:30 來源:億速云 閱讀:227 作者:chen 欄目:開發技術

本篇內容介紹了“Go怎么實現協程超時控制”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

目錄
  • Go 協程超時控制

  • Select 超時控制

    • go timer 計時器

    • go context

Go 協程超時控制

  • Select 阻塞方式

  • Context 方式

先說個場景:

假設業務中 A 服務需要調用 服務B,要求設置 5s 超時,那么如何優雅實現?

Select 超時控制

考慮是否可以用 select + time.After 方式進行實現

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

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

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

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

運行結果:

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

go timer 計時器

這個是 timer 類似的計時器實現,通用也是通過通道來發送數據。

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

go context

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

  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)

關鍵看業務代碼: resp := DoHttp(timeoutCtx, info.req) 業務代碼中包含 http 調用 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")
 }
}

運行結果:

=== 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 會在當前工作完成或者上下文被取消之后關閉,多次調用 Done 方法會返回同一個 Channel;

  • Err — 返回 context.Context 結束的原因,它只會在 Done 返回的 Channel 被關閉時才會返回非空的值;

    • 如果 context.Context 被取消,會返回 Canceled 錯誤;

    • 如果 context.Context 超時,會返回 DeadlineExceeded 錯誤;

  • Value — 從 context.Context 中獲取鍵對應的值,對于同一個上下文來說,多次調用 Value 并傳入相同的 Key 會返回相同的結果,該方法可以用來傳遞請求特定的數據;

“Go怎么實現協程超時控制”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

go
AI

项城市| 江门市| 义马市| 镇坪县| 蓝田县| 军事| 灵武市| 云龙县| 陆川县| 沭阳县| 固原市| 定襄县| 莱阳市| 六枝特区| 公安县| 康马县| 腾冲县| 靖西县| 镇康县| 巩留县| 迁西县| 广平县| 辽阳市| 襄城县| 宁化县| 明溪县| 荥经县| 阿尔山市| 天峻县| 奉贤区| 南岸区| 五常市| 巴林右旗| 伊吾县| 澄迈县| 武城县| 牙克石市| 嵩明县| 德保县| 佛教| 邵阳市|