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

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

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

前言

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

基本用法

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

# 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 的截止時間,
  • Done() 方法用于返回一個只讀的 channel,用于通知當(dāng)前 Context 是否已經(jīng)被取消,
  • Err() 方法用于獲取 Context 取消的原因,
  • Value() 方法用于獲取 Context 中保存的鍵值對數(shù)據(jù)。

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

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

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

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

Context控制goroutine的生命周期

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

eg,看一下下方代碼:

func users(ctx context.Context, req *Request) {
    // 啟動一個 goroutine 來處理請求
    go func() {
        // 處理請求...
    }()
}

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

func users(ctx context.Context, req *Request) {
    // 啟動一個 goroutine 來處理請求
    go func(ctx context.Context) {
        // 處理請求...
    }(ctx)
}

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

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

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

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

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

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

注:

Context 中保存的鍵值對數(shù)據(jù)應(yīng)該是線程安全的,因為它們可能會在多個 goroutine 中同時訪問。

使用 WithCancel() 取消操作

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

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

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

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

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

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

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

注:

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

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

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

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

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

注:

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

Context的傳遞

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

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

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

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

注:

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

總結(jié)

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

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

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

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

相關(guān)文章

  • Go流程控制代碼詳解

    Go流程控制代碼詳解

    這篇文章主要詳細(xì)介紹了Go流程控制,文章通過實例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價值 ,需要的朋友可以參考下
    2023-04-04
  • Go語言TCP從原理到代碼實現(xiàn)詳解

    Go語言TCP從原理到代碼實現(xiàn)詳解

    這篇文章主要為大家介紹了Go語言TCP從原理到代碼實現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • golang 跳出for循環(huán)操作

    golang 跳出for循環(huán)操作

    這篇文章主要介紹了golang 跳出for循環(huán)操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Go語言中sync.Cond使用詳解

    Go語言中sync.Cond使用詳解

    本文主要介紹了Go語言中sync.Cond使用詳解,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • 在Go中編寫測試代碼的方法總結(jié)

    在Go中編寫測試代碼的方法總結(jié)

    在程序開發(fā)過程中,測試是非常重要的一環(huán),甚至有一種開發(fā)模式叫?TDD,先編寫測試,再編寫功能代碼,通過測試來推動整個開發(fā)的進(jìn)行,可見測試在開發(fā)中的重要程度,為此,Go提供了testing框架來方便我們編寫測試,本文將向大家介紹在Go中如何編寫測試代碼
    2023-07-07
  • Go 1.21新增的slices包中切片函數(shù)用法詳解

    Go 1.21新增的slices包中切片函數(shù)用法詳解

    Go 1.21新增的 slices 包提供了很多和切片相關(guān)的函數(shù),可以用于任何類型的切片,本文通過代碼示例為大家介紹了部分切片函數(shù)的具體用法,感興趣的小伙伴可以了解一下
    2023-08-08
  • GoLang sync.Pool簡介與用法

    GoLang sync.Pool簡介與用法

    這篇文章主要介紹了GoLang sync.Pool簡介與用法,Pool是可伸縮、并發(fā)安全的臨時對象池,用來存放已經(jīng)分配但暫時不用的臨時對象,通過對象重用機(jī)制,緩解GC壓力,提高程序性能
    2023-01-01
  • Go語言七篇入門教程一簡介初識

    Go語言七篇入門教程一簡介初識

    本篇是Go語言七篇入門系列第一篇Go語言初識及簡單介紹,從現(xiàn)在開始一起打開Go語言的學(xué)習(xí)大門吧,希望能夠有所幫助,祝大家多多進(jìn)步
    2021-11-11
  • 深入了解Golang中reflect反射的使用

    深入了解Golang中reflect反射的使用

    這篇文章主要介紹了深入了解Golang中reflect反射的使用,Go語言中的反射是一種機(jī)制,可以在運(yùn)行時動態(tài)地獲取類型信息和操作對象,以及調(diào)用對象的方法和屬性等,需要詳細(xì)了解可以參考下文
    2023-05-05
  • Go條件控制語句詳解(if-else、switch和select)

    Go條件控制語句詳解(if-else、switch和select)

    條件語句用于檢查一個條件是否為真,并根據(jù)條件的真假來決定是否執(zhí)行相應(yīng)的代碼,下面這篇文章主要給大家介紹了關(guān)于Go條件控制語句(if-else、switch和select)的相關(guān)資料,需要的朋友可以參考下
    2024-03-03

最新評論

武义县| 大余县| 梁山县| 新昌县| 满洲里市| 江华| 行唐县| 陈巴尔虎旗| 太和县| 上高县| 乌拉特中旗| 灵武市| 湖北省| 逊克县| 合山市| 乾安县| 渭南市| 宜丰县| 洱源县| 高雄县| 沾化县| 织金县| 马边| 乡宁县| 吉安县| 鱼台县| 明水县| 石台县| 资溪县| 正镶白旗| 平原县| 双辽市| 闻喜县| 恭城| 禹州市| 资源县| 莱西市| 赤水市| 隆昌县| 汝阳县| 九龙城区|