<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Golang基礎(chǔ)筆記十三之context

      本文首發(fā)于公眾號(hào):Hunter后端

      原文鏈接:Golang基礎(chǔ)筆記十三之context

      在 Golang 里,context 包提供了很多比如傳遞截止時(shí)間、取消信號(hào)、傳遞數(shù)據(jù)等操作的標(biāo)準(zhǔn)方式,用于在跨 API 邊界、進(jìn)程和 goroutine之間進(jìn)行。

      這一篇筆記詳細(xì)介紹一下 context 包相關(guān)的一些操作。

      以下是本篇筆記目錄:

      1. Context 接口及作用
      2. 取消傳播
      3. 超時(shí)控制
      4. 截止時(shí)間
      5. 傳遞數(shù)據(jù)

      1、Context 接口及作用

      1. Context 接口

      Context 是 context 包下的一個(gè)接口,其定義如下:

      type Context interface {
          Deadline() (deadline time.Time, ok bool)
          Done() <-chan struct{}
          Err() error
          Value(key any) any
      }
      
      1. Deadline() 返回上下文被取消的時(shí)間
      2. Done() 返回一個(gè)通道,當(dāng)上下文被取消時(shí)關(guān)閉
      3. Error() 返回上下文被取消的原因
      4. Value() 可以獲取相應(yīng)的鍵值對(duì)數(shù)據(jù)

      下面所有的操作都是基于 context.Context 實(shí)現(xiàn)。

      2. context 相關(guān)函數(shù)

      我們可以使用 context 創(chuàng)建一些函數(shù),用來實(shí)現(xiàn)取消、超時(shí)控制、傳遞數(shù)據(jù)等操作。

      1) context.Background()

      根上下文,可以作為所有上下文的起點(diǎn),當(dāng)我們需要實(shí)現(xiàn)取消、超時(shí)控制等功能,都需要定義一個(gè)父級(jí)上下文,這個(gè)時(shí)候我們就可以使用 context.Backgroud() 來創(chuàng)建。

      2) context.TODO()

      當(dāng)我們不確定使用哪個(gè)上下文時(shí),就可以使用 context.TODO(),但是在源代碼中,它的實(shí)現(xiàn)與 context.Backgroud() 是一樣的邏輯。

      3) context.WithCancel(parent)

      創(chuàng)建可以取消的上下文,參數(shù)是父級(jí)上下文,當(dāng)我們調(diào)用一個(gè)函數(shù),并且希望在某些時(shí)候取消這個(gè)調(diào)用,比如超時(shí),這個(gè)時(shí)候我們可以使用這個(gè)函數(shù),并手動(dòng)進(jìn)行取消。

      4) context.WithTimeout(parent, timeout)

      創(chuàng)建有超時(shí)的上下文,參數(shù)是父級(jí)上下文和 time.Duration,當(dāng)我們調(diào)用一個(gè)函數(shù),并且希望在多久以后可以自動(dòng)取消,可以使用這個(gè)函數(shù)。

      5) context.WithDeadline(parent, d)

      創(chuàng)建有截止時(shí)間的上下文,參數(shù)是父級(jí)上下文和 time.Time,當(dāng)我們調(diào)用一個(gè)函數(shù),并且希望在某個(gè)具體的時(shí)間點(diǎn)可以自動(dòng)取消,可以使用這個(gè)函數(shù)。

      6) context.WithValue(parent, key, value)

      創(chuàng)建帶有鍵值對(duì)的上下文,我們希望通過上下文傳遞數(shù)據(jù),就可以使用這個(gè)函數(shù)。

      這里介紹了 context 相關(guān)的一些函數(shù),接下來我們以具體的代碼為示例,分別用這些函數(shù)來實(shí)現(xiàn)對(duì)應(yīng)的功能。

      2、 取消傳播

      我們使用 context.WithCancel() 函數(shù)實(shí)現(xiàn)取消傳播的功能。

      其實(shí)就是取消函數(shù)執(zhí)行的操作,為什么會(huì)說取消傳播,因?yàn)樯舷挛目梢栽诤瘮?shù)調(diào)用中一層一層傳遞,當(dāng)我們?nèi)∠烁舷挛模姓{(diào)用鏈中的上下文都會(huì)被取消。

      context.WithCancel() 的使用代碼示例如下:

      ctx, cancel := context.WithCancel(context.Background())
      

      這個(gè)函數(shù)返回兩個(gè)結(jié)果,一個(gè)是上下文參數(shù),一個(gè)是取消函數(shù),我們可以使用取消函數(shù)在特定節(jié)點(diǎn)取消這個(gè)上下文,這里取消操作需要我們手動(dòng)執(zhí)行。

      下面我們實(shí)現(xiàn)一個(gè)取消操作,我們調(diào)用兩個(gè)函數(shù),這兩個(gè)函數(shù)隨機(jī)執(zhí)行一段時(shí)間,然后某個(gè)函數(shù)先返回結(jié)果,返回之后我們立馬執(zhí)行上下文的取消操作,

      package main
      
      import (
          "context"
          "fmt"
          "math/rand"
          "time"
      )
      
      func F1(ctx context.Context, ch chan string) {
          sleepSeconds := rand.Intn(3)
          time.Sleep(time.Duration(sleepSeconds) * time.Second)
          ch <- "f1 result"
      }
      
      func F2(ctx context.Context, ch chan string) {
          sleepSeconds := rand.Intn(3)
          time.Sleep(time.Duration(sleepSeconds) * time.Second)
          ch <- "f2 result"
      }
      
      func CallF1(ctx context.Context, ch chan string) {
          chF1 := make(chan string)
          go F1(ctx, chF1)
      
          select {
          case result := <-chF1:
              ch <- result
          case <-ctx.Done():
              fmt.Println("F1 函數(shù)調(diào)用超時(shí)")
          }
      }
      
      func CallF2(ctx context.Context, ch chan string) {
          chF2 := make(chan string)
          go F2(ctx, chF2)
      
          select {
          case result := <-chF2:
              ch <- result
          case <-ctx.Done():
              fmt.Println("F2 函數(shù)調(diào)用超時(shí)")
          }
      }
      
      func main() {
          ctx, cancel := context.WithCancel(context.Background())
          defer cancel()
      
          ch1 := make(chan string)
          ch2 := make(chan string)
          go CallF1(ctx, ch1)
          go CallF2(ctx, ch2)
      
          select {
          case r1 := <-ch1:
              fmt.Println("f1 調(diào)用完成: ", r1)
              cancel()
          case r2 := <-ch2:
              fmt.Println("f2 調(diào)用完成: ", r2)
              cancel()
          }
      }
      

      在這里,我們目標(biāo)調(diào)用函數(shù)為 F1()F2(),使用 CallF1()CallF2() 作為中間調(diào)用函數(shù),在其中使用 select-case 等待目標(biāo)函數(shù)返回結(jié)果,并同時(shí)監(jiān)聽 ctx.Done() 判斷 ctx 是否已經(jīng)取消。

      同時(shí)在 main() 函數(shù)中監(jiān)聽 ch1 和 ch2 判斷哪個(gè)通道先返回結(jié)果,監(jiān)聽到返回結(jié)果馬上取消 ctx 上下文,main() 函數(shù)就可以接著往下執(zhí)行,避免兩個(gè)目標(biāo)函數(shù)其中一個(gè)長(zhǎng)時(shí)間執(zhí)行。

      這里需要注意的是,中間函數(shù) CallF1() 和 CallF2() 雖然被取消了,但 F1()、F2() 作為執(zhí)行的 goroutine 并沒有取消執(zhí)行,如果有取消的需求,可以在 F() 函數(shù)內(nèi)部伺機(jī)監(jiān)聽 ctx.Done() 以提前退出函數(shù)。

      3、 超時(shí)控制

      我們使用 context.WithTimeout(parent, timeout) 可以實(shí)現(xiàn)超時(shí)控制。

      下面實(shí)現(xiàn)一個(gè)功能為,調(diào)用某個(gè)函數(shù),并給一秒的超時(shí)時(shí)間,超過時(shí)間則進(jìn)行超時(shí)處理,避免長(zhǎng)時(shí)間堵塞,其中目標(biāo)執(zhí)行函數(shù)為 TargetFunc,其中,隨機(jī) sleep 三秒內(nèi)的時(shí)間。

      整體代碼如下:

      package main
      
      import (
          "context"
          "fmt"
          "math/rand"
          "time"
      )
      
      func TargetFunc() string {
          sleepSeconds := rand.Intn(3)
          time.Sleep(time.Duration(sleepSeconds) * time.Second)
          return "result"
      }
      
      func CallFunc(ch chan string) {
          ch <- TargetFunc()
      }
      
      func main() {
          ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
          defer cancel()
      
          ch := make(chan string)
          defer close(ch)
      
          go CallFunc(ch)
      
          select {
          case result := <-ch:
              fmt.Println("result: ", result)
          case <-ctx.Done():
              fmt.Println("函數(shù)調(diào)用超時(shí)")
          }
      }
      

      其中,TargetFunc 函數(shù)內(nèi)部的邏輯為隨機(jī)休息三秒內(nèi)的時(shí)間,可能導(dǎo)致超時(shí),也可能不超時(shí)。

      CallFunc() 函數(shù)用作中間函數(shù),用于獲取目標(biāo)函數(shù)調(diào)用結(jié)果并通過 channel 返回。

      在 main 函數(shù)中,首先定義一個(gè)有超時(shí)時(shí)間的上下文,設(shè)置了一秒超時(shí),然后定義一個(gè)通道,將其傳給 CallFunc() 用于返回?cái)?shù)據(jù)。

      之后通過 select-case 操作,進(jìn)入循環(huán)等待狀態(tài),用于判斷 goroutine 中的 channel 和 ctx 的超時(shí)哪個(gè)先返回結(jié)果。

      如果 TargetFunc 函數(shù)調(diào)用時(shí)間過長(zhǎng),ctx 超時(shí)控制的上下文先到期,那么則會(huì)打印出 函數(shù)調(diào)用超時(shí) 的信息,否則會(huì)打印出函數(shù)調(diào)用返回的結(jié)果。

      4、 截止時(shí)間

      我們可以使用 context.WithDeadline(parent, d) 函數(shù)實(shí)現(xiàn)一個(gè)有截止時(shí)間的上下文,它的調(diào)用參數(shù)第二個(gè)為 d,是一個(gè)具體的 time.Time 類型。

      但其實(shí),在背后的源碼中,context.WithTimeout() 函數(shù)會(huì)將其中的 time.Duration 參數(shù)處理通過 time.Now().Add(timeout) 的方式處理成 time.Time 然后再調(diào)用 WithDeadline 函數(shù),所以超時(shí)控制和截止時(shí)間這兩個(gè)函數(shù)在本質(zhì)上的邏輯是一致的。

      所以這里我們的代碼示例,也只是把輸入的參數(shù)修改一下,即可實(shí)現(xiàn)功能,如下:

      deadline := time.Now().Add(1 * time.Second)
      ctx, cancel := context.WithDeadline(context.Background(), deadline)
      

      5、 傳遞數(shù)據(jù)

      我們可以通過 context.WithValue() 函數(shù)實(shí)現(xiàn)傳遞數(shù)據(jù)的功能,這個(gè)函數(shù)接收三個(gè)參數(shù),父級(jí)上下文,key 和 value,以下是使用示例:

      ctx := context.Background()
      
      ctxWithValue := context.WithValue(ctx, "str1", "value1")
      ctxWithValue = context.WithValue(ctxWithValue, "slice", []int{1, 2, 3})
      
      

      在獲取數(shù)據(jù)的時(shí)候,我們可以使用 ctx.Value() 函數(shù)獲取:

      func ProcessCtxValue(ctx context.Context) {
          value1 := ctx.Value("str1")
          fmt.Println("str1 value: ", value1)
      
          value2 := ctx.Value("slice")
          fmt.Println("slice value: ", value2)
      }
      

      但是在真正用到這些數(shù)據(jù)的時(shí)候,我們還需要對(duì) value 進(jìn)行類型判斷,可以直接如下操作:

      func ProcessCtxValue(ctx context.Context) {
          value1, ok := ctx.Value("str1").(string)
          if ok {
              fmt.Println("str1 value: ", value1)
          }
      
          value2 := ctx.Value("slice").([]int)
          if ok {
              fmt.Println("slice value: ", value2, value2[1])
          }
      }
      
      posted @ 2025-07-21 21:07  XHunter  閱讀(346)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 国产欧美va欧美va在线| 叙永县| 国产精品成人一区二区三区| 欧美牲交videossexeso欧美| 国产精品午夜福利在线观看| 真人性囗交视频| 国产成人精品午夜在线观看| 亚洲男人第一无码av网站| 亚洲成人av免费一区| 思思久99久女女精品| 欧美精品人人做人人爱视频| 国产精品久久久久影院亚瑟| 亚洲精品一区国产精品| 丁香婷婷综合激情五月色| 天堂а√8在线最新版在线| 国产精品一区中文字幕| 另类专区一区二区三区| 成年女人片免费视频播放A| 天天综合亚洲色在线精品| 国产精品不卡一区二区在线| 4399理论片午午伦夜理片| 欧美高清狂热视频60一70| 男受被做哭激烈娇喘gv视频 | 精品少妇无码一区二区三批 | 国产四虎永久免费观看| 国产精品视频一区二区噜噜| 国产精品免费无遮挡无码永久视频| 天堂一区二区三区av| 亚洲av熟女国产一二三| 精品 日韩 国产 欧美 视频| 国产精品剧情亚洲二区| 精品人妻中文无码av在线| 亚洲午夜成人精品电影在线观看| 木兰县| 国产成年码av片在线观看| 精品久久久久久无码人妻蜜桃 | 日韩AV高清在线看片| 边吃奶边添下面好爽| 日韩精品国产另类专区| 日韩一区二区大尺度在线| 草草浮力影院|