国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Golang 如何基于現(xiàn)有的 context 創(chuàng)建新的 context?

這篇具有很好參考價值的文章主要介紹了Golang 如何基于現(xiàn)有的 context 創(chuàng)建新的 context?。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

目錄

基于現(xiàn)有的 context 創(chuàng)建新的 context

現(xiàn)有創(chuàng)建方法的問題

Go 1.21 中的 context.WithoutCancel 函數(shù)

Go 版本低于 1.21 該怎么辦?


在 Golang 中,context 包提供了創(chuàng)建和管理上下文的功能。當(dāng)需要基于現(xiàn)有的 context.Context 創(chuàng)建新的 context 時,通常是為了添加額外的控制信息或為了滿足特定的生命周期需求。

基于現(xiàn)有的 context 創(chuàng)建新的 context

可以基于現(xiàn)有的 context.Context 創(chuàng)建一個新的 context,對應(yīng)的函數(shù)有 context.WithCancel、context.WithDeadline、context.WithTimeout 或 context.WithValue。這些函數(shù)會返回一個新的 context.Context 實例,繼承了原來 context 的行為,并添加了新的行為或值。使用 context.WithValue 函數(shù)創(chuàng)建的簡單示例代碼如下:

package main

import "context"

func main() {
	// 假設(shè)已經(jīng)有了一個context ctx
	ctx := context.Background()
	// 可以通過context.WithValue創(chuàng)建一個新的context
	key := "myKey"
	value := "myValue"
	newCtx := context.WithValue(ctx, key, value)
	// 現(xiàn)在newCtx包含了原始ctx的所有數(shù)據(jù),加上新添加的鍵值對
}

使用 context.WithCancel 函數(shù)創(chuàng)建,簡單示例代碼如下:

package main

import "context"

func main() {
    // 假設(shè)已經(jīng)有了一個context ctx
    ctx := context.Background()
    // 創(chuàng)建一個可取消的context
    newCtx, cancel := context.WithCancel(ctx)
    // 當(dāng)完成了newCtx的使用,可以調(diào)用cancel來取消它
    // 這將釋放與該context相關(guān)的資源
    defer cancel()
}

現(xiàn)有創(chuàng)建方法的問題

先說一個使用場景:一個接口處理完基本的任務(wù)之后,后續(xù)一些處理的任務(wù)放使用新開的 Goroutine 來處理,這時候會基于當(dāng)前的 context 創(chuàng)建一個 context(可以使用上面提到的方法來創(chuàng)建) 給 Goroutine 使用,也不需要控制 Goroutine 的超時時間。

這種場景下,Goroutine 的聲明周期一般都會比這個接口的生命周期長,這就會出現(xiàn)一個問題——當(dāng)前接口請求所屬的?Goroutine 退出后會導(dǎo)致 context 被 cancel,進(jìn)而導(dǎo)致新開的 Goroutine 中的 context 跟著被 cancel, 從而導(dǎo)致程序異常。看一個示例:

package main

import (
    "bytes"
    "context"
    "errors"
    "fmt"
    "io"
    "net/http"

    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.New()
    r.GET("/test", func(c *gin.Context) {
       // 父 context,有使用取消功能
       ctx, cancel := context.WithCancel(c)
       defer cancel()

       // 創(chuàng)建子 context 給新開的 Goroutine 使用
       ctxCopy, _ := context.WithCancel(ctx)
       go func() {
          err := TestPost(ctxCopy)
          fmt.Println(err)
       }()
    })
    r.Run(":8080")
}

func TestPost(ctx context.Context) error {
    fmt.Println("goroutine...")
    buffer := bytes.NewBuffer([]byte(`{"xxx":"xxx"}`))
    request, err := http.NewRequest("POST", "http://xxx.luduoxin.com/xxx", buffer)
    if err != nil {
       return err
    }
    request.Header.Set("Content-Type", "application/json")
    client := http.Client{}
    rsp, err := client.Do(request.WithContext(ctx))
    if err != nil {
       return err
    }
    defer func() {
       _ = rsp.Body.Close()
    }()
    if rsp.StatusCode != http.StatusOK {
       return errors.New("response exception")
    }
    _, err = io.ReadAll(rsp.Body)
    if err != nil {
       return err
    }
    return nil
}

運行代碼,在瀏覽器中訪問?http://127.0.0.1:8080/test,控制臺會打印如下錯誤信息:

goroutine...
Post "http://xxx.luduoxin.com/xxx": context canceled

可以看出,因為父級 context 被 cancel,導(dǎo)致子 context 也被 cancel,從而導(dǎo)致程序異常。因此,需要一種既能繼承父 context 所有的 value 信息,又能去除父級 context 的 cancel 機制的創(chuàng)建函數(shù)。

Go 1.21 中的 context.WithoutCancel 函數(shù)

這種函數(shù)該如何實現(xiàn)呢?其實 Golang 從 1.21 版本開始為我們提供了這樣一個函數(shù),就是 context 包中的?WithoutCancel 函數(shù)。源代碼如下:

func WithoutCancel(parent Context) Context {
    if parent == nil {
       panic("cannot create context from nil parent")
    }
    return withoutCancelCtx{parent}
}

type withoutCancelCtx struct {
    c Context
}

func (withoutCancelCtx) Deadline() (deadline time.Time, ok bool) {
    return
}

func (withoutCancelCtx) Done() <-chan struct{} {
    return nil
}

func (withoutCancelCtx) Err() error {
    return nil
}

func (c withoutCancelCtx) Value(key any) any {
    return value(c, key)
}

func (c withoutCancelCtx) String() string {
    return contextName(c.c) + ".WithoutCancel"
}

原理其實很簡單,主要功能是創(chuàng)建一個新的 context 類型,繼承了父 context 的所有屬性,但重寫了 Deadline、Done、Err、Value 幾個方法,當(dāng)父 context 被取消時不會觸發(fā)任何操作。

Go 版本低于 1.21 該怎么辦?

如果 Go 版本低于 1.21 其實也很好辦,按照 Go 1.21 中的實現(xiàn)方式自己實現(xiàn)一個就可以了,代碼可以進(jìn)一步精簡,示例代碼如下:

func WithoutCancel(parent Context) Context {
    if parent == nil {
       panic("cannot create context from nil parent")
    }
    return withoutCancelCtx{parent}
}

type withoutCancelCtx struct {
    context.Context
}

func (withoutCancelCtx) Deadline() (deadline time.Time, ok bool) {
    return
}

func (withoutCancelCtx) Done() <-chan struct{} {
    return nil
}

func (withoutCancelCtx) Err() error {
    return nil
}

使用自己實現(xiàn)的這個版本再跑一下之前的示例,代碼如下:

package main

import (
    "bytes"
    "context"
    "errors"
    "fmt"
    "io"
    "net/http"
    "time"

    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.New()
    r.GET("/test", func(c *gin.Context) {
       // 父 context,有使用取消功能
       ctx, cancel := context.WithCancel(c)
       defer cancel()

       // 創(chuàng)建子 context 給新開的 Goroutine 使用
       ctxCopy := WithoutCancel(ctx)
       go func() {
          err := TestPost(ctxCopy)
          fmt.Println(err)
       }()
    })
    r.Run(":8080")
}

func WithoutCancel(parent Context) Context {
    if parent == nil {
       panic("cannot create context from nil parent")
    }
    return withoutCancelCtx{parent}
}

type withoutCancelCtx struct {
    context.Context
}

func (withoutCancelCtx) Deadline() (deadline time.Time, ok bool) {
    return
}

func (withoutCancelCtx) Done() <-chan struct{} {
    return nil
}

func (withoutCancelCtx) Err() error {
    return nil
}

func TestPost(ctx context.Context) error {
    fmt.Println("goroutine...")
    buffer := bytes.NewBuffer([]byte(`{"xxx":"xxx"}`))
    request, err := http.NewRequest("POST", "http://xxx.luduoxin.com/xxx", buffer)
    if err != nil {
       return err
    }
    request.Header.Set("Content-Type", "application/json")
    client := http.Client{}
    rsp, err := client.Do(request.WithContext(ctx))
    if err != nil {
       return err
    }
    defer func() {
       _ = rsp.Body.Close()
    }()
    if rsp.StatusCode != http.StatusOK {
       return errors.New("response exception")
    }
    _, err = io.ReadAll(rsp.Body)
    if err != nil {
       return err
    }
    return nil
}

type Context interface {
    Deadline() (deadline time.Time, ok bool)
    Done() <-chan struct{}
    Err() error
    Value(key any) any
}

運行代碼,在瀏覽器中訪問 http://127.0.0.1:8080/test,發(fā)現(xiàn)不再報父 context 被 cancel 導(dǎo)致的報錯了。文章來源地址http://www.zghlxwxcb.cn/news/detail-797759.html

到了這里,關(guān)于Golang 如何基于現(xiàn)有的 context 創(chuàng)建新的 context?的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • git 如何創(chuàng)建新的遠(yuǎn)程分支,并將本地代碼 push 到新的分支

    git 如何創(chuàng)建新的遠(yuǎn)程分支,并將本地代碼 push 到新的分支

    1、可以通過git branch -r 命令查看遠(yuǎn)端庫的分支情況 2、從已有的分支創(chuàng)建新的分支(如從master分支),創(chuàng)建一個 duanjiwang 分支 但此時并沒有在遠(yuǎn)程倉庫上創(chuàng)建分支 如圖所示 還是只有一個 master 分支 3、建立本地到遠(yuǎn)端倉庫的鏈接 --這樣代碼才能提交上去 使用命令行 4、git 強制提交

    2024年02月12日
    瀏覽(21)
  • Eplan2022 復(fù)制已有的宏文件生成新的原理圖宏文件

    Eplan2022 復(fù)制已有的宏文件生成新的原理圖宏文件

    下圖所示為wago的787-722穩(wěn)壓電源,我們可以從官網(wǎng)下載到相應(yīng)的eplan宏文件并導(dǎo)入數(shù)據(jù)源庫。但是能下載到eplan宏文件的只是少部分公司的部件。那么沒有宏文件的部件該怎么辦? 接下來以明緯開關(guān)電源 NDR-120-24為例,創(chuàng)建一個宏文件。選擇【主數(shù)據(jù)】?【管理】,進(jìn)入部件管

    2024年02月03日
    瀏覽(104)
  • git基于原有的分支拉?。▌?chuàng)建)一個新的分支

    git checkout -b newbranch origin/oldbranchname newbranch:你要創(chuàng)建的分支的名子 oldbranchname:原來的分支(你要基于的分支) git push --set-upstream origin newbranch newbranch:你剛剛創(chuàng)建的新分支的名字 git push origin newbranch 或者直接 git push newbranch:你剛剛創(chuàng)建的新分支的名字

    2024年02月15日
    瀏覽(82)
  • idea 2023.3.2版本如何創(chuàng)建新的maven項目

    idea 2023.3.2版本如何創(chuàng)建新的maven項目

    1.首先點擊new--project ?2.填寫相關(guān)項目名,存放的地址等 ?3.創(chuàng)建后的效果 4.添加maven依賴,若依賴一直下載不下來,注意在setting中配置一下maven(根據(jù)自己的情況配置)以及jdk等 ? ??根據(jù)自己的實際安裝地址,進(jìn)行maven相關(guān)配置 配置jdk ?配置jre 5.創(chuàng)建下的maven項目沒有Resour

    2024年02月15日
    瀏覽(27)
  • react后端開發(fā):如何根據(jù)特定ID創(chuàng)建新的用戶信息?

    以音樂app開發(fā)為例,我們想要在想要創(chuàng)建新的唱片庫,就需要使用Post連接服務(wù)器端新建唱片ID,并在該ID處插入唱片信息。怎么做呢? 使用create同時創(chuàng)建id和唱片信息 不過在這之前,我們一般先需要進(jìn)行判斷,新寫入的唱片是否存在,比如某用戶已經(jīng)上傳了周杰倫的青花瓷,

    2024年01月23日
    瀏覽(18)
  • Golang:淺析Context包

    在golang官方文檔context package - context - Go Packages中是這樣介紹context包的: 在context包中定義了context類型來在不同的Goroutine 之間傳遞上下文,攜帶截止時間、取消信號以及攜帶上下文的系統(tǒng)參數(shù)(k-v)的類型。對服務(wù)器的傳入請求應(yīng)該創(chuàng)建上下文,對服務(wù)器的傳出調(diào)用應(yīng)該接受上

    2024年02月06日
    瀏覽(19)
  • golang Context應(yīng)用舉例

    golang Context應(yīng)用舉例

    ? golang標(biāo)準(zhǔn)庫里Context實際上是一個接口(即一種編程規(guī)范、 一種約定)。 ? 通過查看源碼里的注釋,我們得到如下約定: Done()函數(shù)返回一個只讀管道,且管道里不存放任何元素(struct{}),所以用這個管道就是為了實現(xiàn)阻塞 Deadline()用來記錄到期時間,以及是否到期。 Err()用來

    2024年02月08日
    瀏覽(19)
  • golang中context詳解

    編碼中遇到上下文信息傳遞,并發(fā)信息取消等,記錄下在go語言中context包的使用。 在Go語言中,context包提供了一種在程序中傳遞截止日期、取消信號、請求范圍數(shù)據(jù)和其他元數(shù)據(jù)的方式。context包的核心類型是Context接口,它定義了在執(zhí)行上下文中傳遞的方法。Context接口的主要

    2024年01月21日
    瀏覽(14)
  • golang之context實用記錄

    簡言 WithCancel()函數(shù)接受一個 Context 并返回其子Context和取消函數(shù)cancel 新創(chuàng)建協(xié)程中傳入子Context做參數(shù),且需監(jiān)控子Context的Done通道,若收到消息,則退出 需要新協(xié)程結(jié)束時,在外面調(diào)用 cancel 函數(shù),即會往子Context的Done通道發(fā)送消息 注意:當(dāng) 父Context的 Done() 關(guān)閉的時候,子

    2024年02月09日
    瀏覽(19)
  • 【golang】Context超時控制與原理

    【golang】Context超時控制與原理

    在Go語言圈子中流行著一句話: Never start a goroutine without knowing how it will stop。 翻譯:如果你不知道協(xié)程如何退出,就不要使用它。 在創(chuàng)建協(xié)程時,我們可能還會再創(chuàng)建一些別的子協(xié)程,那么這些協(xié)程的退出就成了問題。在Go1.7之后,Go官方引入了Context來實現(xiàn)協(xié)程的退出。不僅

    2024年01月22日
    瀏覽(19)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包