欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go語言基礎(chǔ)學(xué)習(xí)之Context的使用詳解

 更新時(shí)間:2023年05月10日 10:41:15   作者:程序員祝融  
在Go語言中,Context是一個(gè)非常重要的概念,它用于在不同的?goroutine?之間傳遞請(qǐng)求域的相關(guān)數(shù)據(jù),本文將深入探討Go語言中?Context特性和Context的高級(jí)使用方法,希望對(duì)大家有所幫助

前言

在 Go 語言中,Context 是一個(gè)非常重要的概念,它用于在不同的 goroutine 之間傳遞請(qǐng)求域的相關(guān)數(shù)據(jù),并且可以用來控制 goroutine 的生命周期和取消操作。本文將深入探討 Go 語言中 Context 特性 和 Context 的高級(jí)使用方法。

基本用法

在 Go 語言中,Context 被定義為一個(gè)接口類型,它包含了三個(gè)方法:

# go version 1.18.10
type Context interface {
    Deadline() (deadline time.Time, ok bool)
    Done() <-chan struct{}
    Err() error
      Value(key any) any
}
  • Deadline() 方法用于獲取 Context 的截止時(shí)間,
  • Done() 方法用于返回一個(gè)只讀的 channel,用于通知當(dāng)前 Context 是否已經(jīng)被取消,
  • Err() 方法用于獲取 Context 取消的原因,
  • Value() 方法用于獲取 Context 中保存的鍵值對(duì)數(shù)據(jù)。

我們?nèi)粘>帉懘a時(shí),Context 對(duì)象會(huì)被被約定作為函數(shù)的第一個(gè)參數(shù)傳遞,eg:

func users(ctx context.Context, request *Request) {
    // ... code
}

在函數(shù)中,可以通過 ctx 參數(shù)來獲取相關(guān)的 Context 數(shù)據(jù),舉個(gè)超時(shí)的 eg:

deadline, ok := ctx.Deadline()
if ok && deadline.Before(time.Now()) {
    // 超時(shí)
    return
}

Context控制goroutine的生命周期

在 Go 語言中,goroutine 是一種非常常見的并發(fā)編程模型,而 Context 可以被用來控制 goroutine 的生命周期,從而避免出現(xiàn) goroutine 泄漏或者不必要的等待操作。

eg,看一下下方代碼:

func users(ctx context.Context, req *Request) {
    // 啟動(dòng)一個(gè) goroutine 來處理請(qǐng)求
    go func() {
        // 處理請(qǐng)求...
    }()
}

上面的代碼中,我們啟動(dòng)了一個(gè) goroutine 來處理請(qǐng)求,但是沒有任何方式來控制這個(gè) goroutine 的生命周期,如果這個(gè)請(qǐng)求被取消了,那么這個(gè) goroutine 就會(huì)一直存在,直到它完成為止。為了避免這種情況的發(fā)生,我們可以使用 Context 來控制 goroutine 的生命周期,eg:

func users(ctx context.Context, req *Request) {
    // 啟動(dòng)一個(gè) goroutine 來處理請(qǐng)求
    go func(ctx context.Context) {
        // 處理請(qǐng)求...
    }(ctx)
}

在上面的代碼中,我們將 Context 對(duì)象作為參數(shù)傳遞給了 goroutine 函數(shù),這樣在請(qǐng)求被取消時(shí),goroutine 就可以及時(shí)退出。

使用 WithValue() 傳遞數(shù)據(jù)

除了用于控制 goroutine 的生命周期,Context 還可以被用來在不同的 goroutine 之間傳遞請(qǐng)求域的相關(guān)數(shù)據(jù)。為了實(shí)現(xiàn)這個(gè)目的,我們可以使用 Context 的 WithValue() 方法,eg:

type key int
const (
    userKey key = iota
)
func users(ctx context.Context, req *Request) {
    // 從請(qǐng)求中獲取用戶信息
    user := req.GetUser
    // 將用戶信息保存到 Context 中
    ctx = context.WithValue(ctx, userKey, user)
    // 啟動(dòng)一個(gè) goroutine 來處理請(qǐng)求
    go func(ctx context.Context) {
        // 從 Context 中獲取用戶信息
        user := ctx.Value(userKey).(*User)
        // 處理請(qǐng)求...
    }(ctx)
}

在上面的代碼中,我們定義了一個(gè) key類型的常量 userKey,然后在 users()函數(shù)中將用戶信息保存到了 Context 中,并將 Context 對(duì)象傳遞給了 goroutine 函數(shù)。

在 goroutine 函數(shù)中,我們使用 ctx.Value()方法來獲取 Context 中保存的用戶信息。

注:

Context 中保存的鍵值對(duì)數(shù)據(jù)應(yīng)該是線程安全的,因?yàn)樗鼈兛赡軙?huì)在多個(gè) goroutine 中同時(shí)訪問。

使用 WithCancel() 取消操作

除了控制 goroutine 的生命周期和傳遞數(shù)據(jù)之外,Context 還可以被用來執(zhí)行取消操作。為了實(shí)現(xiàn)這個(gè)目的,我們可以使用 Context 的 WithCancel()方法,eg:

func users(ctx context.Context, req *Request) {
    // 創(chuàng)建一個(gè)可以取消的 Context 對(duì)象
    ctx, cancel := context.WithCancel(ctx)
    // 啟動(dòng)一個(gè) goroutine 來處理請(qǐng)求
    go func(ctx context.Context) {
        // 等待請(qǐng)求完成或者被取消
        select {
        case <-time.After(time.Second):
            // 請(qǐng)求完成
            fmt.Println("Request finish")
        case <-ctx.Done():
            // 請(qǐng)求被取消
            fmt.Println("Request canceled")
        }
    }(ctx)
    // 等待一段時(shí)間后取消請(qǐng)求
    time.Sleep(time.Millisecond * 800)
    cancel()
}

在上面的代碼中,我們使用 WithCancel() 方法創(chuàng)建了一個(gè)可以取消的 Context 對(duì)象,并將取消操作封裝在了一個(gè) cancel() 函數(shù)中。然后我們啟動(dòng)了一個(gè) goroutine 函數(shù),使用 select 語句等待請(qǐng)求完成或者被取消,最后在主函數(shù)中等待一段時(shí)間后調(diào)用 cancel() 函數(shù)來取消請(qǐng)求。

使用 WithDeadline() 設(shè)置截止時(shí)間

除了使用 WithCancel() 方法進(jìn)行取消操作之外,Context 還可以被用來設(shè)置截止時(shí)間,以便在超時(shí)的情況下取消請(qǐng)求。為了實(shí)現(xiàn)這個(gè)目的,我們可以使用 Context 的 WithDeadline() 方法,eg:

func users(ctx context.Context, req *Request) {
    // 設(shè)置請(qǐng)求的截止時(shí)間為當(dāng)前時(shí)間加上 1 秒鐘
    ctx, cancel := context.WithDeadline(ctx, time.Now().Add(time.Second))
    // 啟動(dòng)一個(gè) goroutine 來處理請(qǐng)求
    go func(ctx context.Context) {
        // 等待請(qǐng)求完成或者超時(shí)
        select {
            case <-time.After(time.Millisecond * 500):
            // 請(qǐng)求完成
            fmt.Println("Request finish")
            case <-ctx.Done():
            // 請(qǐng)求超時(shí)或者被取消
            fmt.Println("Request canceled or timed out")
        }
    }(ctx)
    // 等待一段時(shí)間后取消請(qǐng)求
    time.Sleep(time.Millisecond * 1500)
    cancel()
}

在上面的代碼中,我們使用 WithDeadline() 方法設(shè)置了一個(gè)截止時(shí)間為當(dāng)前時(shí)間加上 1 秒鐘的 Context 對(duì)象,并將超時(shí)操作封裝在了一個(gè) cancel() 函數(shù)中。然后我們啟動(dòng)了一個(gè) goroutine 函數(shù),使用 select 語句等待請(qǐng)求完成或者超時(shí),最后在主函數(shù)中等待一段時(shí)間后調(diào)用 cancel() 函數(shù)來取消請(qǐng)求。

注:

在使用 WithDeadline() 方法設(shè)置截止時(shí)間的時(shí)候,如果截止時(shí)間已經(jīng)過期,則 Context 對(duì)象將被立即取消。

使用 WithTimeout() 設(shè)置超時(shí)時(shí)間

除了使用 WithDeadline() 方法進(jìn)行截止時(shí)間設(shè)置之外,Context 還可以被用來設(shè)置超時(shí)時(shí)間。為了實(shí)現(xiàn)這個(gè)目的,我們可以使用 Context 的 WithTimeout() 方法,eg:

func users(ctx context.Context, req *Request) {
    // 設(shè)置請(qǐng)求的超時(shí)時(shí)間為 1 秒鐘
    ctx, cancel := context.WithTimeout(ctx, time.Second)
    // 啟動(dòng)一個(gè) goroutine 來處理請(qǐng)求
    go func(ctx context.Context) {
        // 等待請(qǐng)求完成或者超時(shí)
        select {
        case <-time.After(time.Millisecond * 500):
            // 請(qǐng)求完成
            fmt.Println("Request completed")
        case <-ctx.Done():
            // 請(qǐng)求超時(shí)或者被取消
            fmt.Println("Request canceled or timed out")
        }
    }(ctx)
    // 等待一段時(shí)間后取消請(qǐng)求
    time.Sleep(time.Millisecond * 1500)
    cancel()
}

在上面的代碼中,我們使用 WithTimeout() 方法設(shè)置了一個(gè)超時(shí)時(shí)間為 1 秒鐘的 Context 對(duì)象,并將超時(shí)操作封裝在了一個(gè) cancel() 函數(shù)中。然后我們啟動(dòng)了一個(gè) goroutine 函數(shù),使用 select 語句等待請(qǐng)求完成或者超時(shí),最后在主函數(shù)中等待一段時(shí)間后調(diào)用 cancel() 函數(shù)來取消請(qǐng)求。

注:

需要注意的是,在使用 WithTimeout() 方法設(shè)置超時(shí)時(shí)間的時(shí)候,如果超時(shí)時(shí)間已經(jīng)過期,則 Context 對(duì)象將被立即取消。

Context的傳遞

在一個(gè)應(yīng)用程序中,不同的 goroutine 可能需要共享同一個(gè) Context 對(duì)象。為了實(shí)現(xiàn)這個(gè)目的,Context 對(duì)象可以通過函數(shù)調(diào)用或者網(wǎng)絡(luò)傳輸?shù)确绞竭M(jìn)行傳遞。

例如,我們可以在一個(gè)處理 HTTP 請(qǐng)求的函數(shù)中創(chuàng)建一個(gè) Context 對(duì)象,并將它作為參數(shù)傳遞給一個(gè)數(shù)據(jù)庫(kù)查詢函數(shù),以便在查詢過程中使用這個(gè) Context 對(duì)象進(jìn)行取消操作。代碼 eg:

func users(ctx context.Context, req *Request) {
    // 在處理 HTTP 請(qǐng)求的函數(shù)中創(chuàng)建 Context 對(duì)象
    ctx, cancel := context.WithTimeout(ctx, time.Second)
    defer cancel()
    // 調(diào)用數(shù)據(jù)庫(kù)查詢函數(shù)并傳遞 Context 對(duì)象
    result, err := findUserByName(ctx, req)
    if err != nil {
        // 處理查詢錯(cuò)誤...
    }
    // 處理查詢結(jié)果...
}
func findUserByName(ctx context.Context, req *Request) (*Result, error) {
    // 在數(shù)據(jù)庫(kù)查詢函數(shù)中使用傳遞的 Context 對(duì)象
    rows, err := db.QueryContext(ctx, "SELECT * FROM users WHERE name = ?", req.Name)
    if err != nil {
        // 處理查詢錯(cuò)誤...
      }
      defer rows.Close()
      // 處理查詢結(jié)果...
}

在上面的代碼中,我們?cè)谔幚?HTTP 請(qǐng)求的函數(shù)中創(chuàng)建了一個(gè) Context 對(duì)象,并將它作為參數(shù)傳遞給了一個(gè)數(shù)據(jù)庫(kù)查詢函數(shù) findUserByName()。在 findUserByName() 函數(shù)中,我們使用傳遞的 Context 對(duì)象來調(diào)用 db.QueryContext() 方法進(jìn)行查詢操作。由于傳遞的 Context 對(duì)象可能會(huì)在查詢過程中被取消,因此我們需要在查詢完成后檢查查詢操作的錯(cuò)誤,以便進(jìn)行相應(yīng)的處理。

注:

在進(jìn)行 Context 的傳遞時(shí),我們需要保證傳遞的 Context 對(duì)象是原始 Context 對(duì)象的子 Context,以便在需要取消操作時(shí)能夠同時(shí)取消所有相關(guān)的 goroutine。如果傳遞的 Context 對(duì)象不是原始 Context 對(duì)象的子 Context,則取消操作只會(huì)影響到當(dāng)前 goroutine,而無法取消其他相關(guān)的 goroutine。

總結(jié)

在 Go 語言中,Context 是一個(gè)非常重要的特性,包括其基本用法和一些高級(jí)用法。Context 可以用于管理 goroutine 的生命周期和取消操作,避免出現(xiàn)資源泄漏和死鎖等問題,同時(shí)也可以提高應(yīng)用程序的性能和可維護(hù)性。

在使用 Context 的時(shí)候,需要注意以下幾點(diǎn):

  • 在創(chuàng)建 goroutine 時(shí),需要將原始 Context 對(duì)象作為參數(shù)傳遞給它。
  • 在 goroutine 中,需要使用傳遞的 Context 對(duì)象來進(jìn)行取消操作,以便能夠及時(shí)釋放相關(guān)的資源。
  • Context 的傳遞時(shí),需要保證傳遞的 Context 對(duì)象是原始 Context 對(duì)象的子 Context,以便在需要取消操作時(shí)能夠同時(shí)取消所有相關(guān)的 goroutine。
  • 在使用 WithCancel 和 WithTimeout 方法創(chuàng)建 Context 對(duì)象時(shí),需要及時(shí)調(diào)用 cancel 函數(shù),以便能夠及時(shí)釋放資源。
  • 在一些場(chǎng)景下,可以使用 WithValue 方法將數(shù)據(jù)存儲(chǔ)到 Context 中,以便在不同的 goroutine 之間共享數(shù)據(jù)。

到此這篇關(guān)于Go語言基礎(chǔ)學(xué)習(xí)之Context的使用詳解的文章就介紹到這了,更多相關(guān)Go語言Context內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • go使用Gin框架利用阿里云實(shí)現(xiàn)短信驗(yàn)證碼功能

    go使用Gin框架利用阿里云實(shí)現(xiàn)短信驗(yàn)證碼功能

    這篇文章主要介紹了go使用Gin框架利用阿里云實(shí)現(xiàn)短信驗(yàn)證碼,使用json配置文件及配置文件解析,編寫路由controller層,本文通過代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2021-08-08
  • Golang使用Gin框架實(shí)現(xiàn)HTTP響應(yīng)格式統(tǒng)一處理

    Golang使用Gin框架實(shí)現(xiàn)HTTP響應(yīng)格式統(tǒng)一處理

    在gin框架中,我們可以定義一個(gè)中間件來處理統(tǒng)一的HTTP響應(yīng)格式,本文主要為大家介紹了具體是怎么定義實(shí)現(xiàn)這樣的中間件的,感興趣的小伙伴可以了解一下
    2023-07-07
  • Go語言算法之尋找數(shù)組第二大元素的方法

    Go語言算法之尋找數(shù)組第二大元素的方法

    這篇文章主要介紹了Go語言算法之尋找數(shù)組第二大元素的方法,以實(shí)例形式分析了不排序、只循環(huán)一次來實(shí)現(xiàn)尋找數(shù)組第二大元素的技巧,是比較典型的算法,需要的朋友可以參考下
    2015-02-02
  • Go語言學(xué)習(xí)技巧之如何合理使用Pool

    Go語言學(xué)習(xí)技巧之如何合理使用Pool

    這篇文章主要給大家介紹了關(guān)于Go語言學(xué)習(xí)技巧之如何合理使用Pool的相關(guān)資料,Pool用于存儲(chǔ)那些被分配了但是沒有被使用,而未來可能會(huì)使用的值,以減小垃圾回收的壓力。文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下。
    2017-12-12
  • Go語言編程入門超級(jí)指南

    Go語言編程入門超級(jí)指南

    這篇文章主要介紹了Go語言編程的入門指南,包括對(duì)Go的變量及函數(shù)的基本介紹,需要的朋友可以參考下
    2016-01-01
  • GO語言運(yùn)行環(huán)境下載、安裝、配置圖文教程

    GO語言運(yùn)行環(huán)境下載、安裝、配置圖文教程

    這篇文章主要介紹了GO語言運(yùn)行環(huán)境下載、安裝、配置圖文教程,需要的朋友可以參考下
    2017-02-02
  • Go語言中結(jié)構(gòu)體方法副本傳參與指針傳參的區(qū)別介紹

    Go語言中結(jié)構(gòu)體方法副本傳參與指針傳參的區(qū)別介紹

    這篇文章主要給大家介紹了關(guān)于Go語言中結(jié)構(gòu)體方法副本傳參與指針傳參的區(qū)別的相關(guān)資料,文中先對(duì)GO語言結(jié)構(gòu)體方法跟結(jié)構(gòu)體指針方法的區(qū)別進(jìn)行了一些簡(jiǎn)單的介紹,來幫助大家理解學(xué)習(xí),需要的朋友可以參考下。
    2017-12-12
  • Go 值傳遞與引用傳遞的方法

    Go 值傳遞與引用傳遞的方法

    這篇文章主要介紹了Go 值傳遞與引用傳遞的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-03-03
  • 手把手帶你走進(jìn)Go語言之常量解析

    手把手帶你走進(jìn)Go語言之常量解析

    這篇文章主要介紹了Go語言之常量解析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-09-09
  • GoLang日志監(jiān)控系統(tǒng)實(shí)現(xiàn)

    GoLang日志監(jiān)控系統(tǒng)實(shí)現(xiàn)

    這篇文章主要介紹了GoLang日志監(jiān)控系統(tǒng)的實(shí)現(xiàn)流程,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2022-12-12

最新評(píng)論