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

golang Context應(yīng)用舉例

這篇具有很好參考價值的文章主要介紹了golang Context應(yīng)用舉例。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

?文章來源地址http://www.zghlxwxcb.cn/news/detail-710267.html

Context本質(zhì)

golang標(biāo)準(zhǔn)庫里Context實際上是一個接口(即一種編程規(guī)范、 一種約定)。

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

?

通過查看源碼里的注釋,我們得到如下約定:

  1. Done()函數(shù)返回一個只讀管道,且管道里不存放任何元素(struct{}),所以用這個管道就是為了實現(xiàn)阻塞
  2. Deadline()用來記錄到期時間,以及是否到期。
  3. Err()用來記錄Done()管道關(guān)閉的原因,比如可能是因為超時,也可能是因為被強(qiáng)行Cancel了。
  4. Value()用來返回key對應(yīng)的value,你可以想像成Context內(nèi)部維護(hù)了一個map。

Context實現(xiàn)

go源碼里提供了Context接口的一個具體實現(xiàn),遺憾的是它只是一個空的Context,什么也沒做。

type emptyCtx int

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

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

func (*emptyCtx) Err() error {
    return nil
}

func (*emptyCtx) Value(key any) any {
    return nil
}

?

emptyCtx以小寫開頭,包外不可見,所以golang又提供了Background和TODO這2個函數(shù)讓我們能獲取到emptyCtx。

var (
        background = new(emptyCtx)
        todo       = new(emptyCtx)
)
func Background() Context {
        return background
}
func TODO() Context {
        return todo
}

?

backgroud和todo明明是一模一樣的東西,就是emptyCtx,為什么要搞2個呢?真心求教,知道的同學(xué)請在評論區(qū)告訴我。

emptyCtx有什么用?創(chuàng)建Context時通常需要傳遞一個父Context,emptyCtx用來充當(dāng)最初的那個Root Context。

With Value

當(dāng)業(yè)務(wù)邏輯比較復(fù)雜,函數(shù)調(diào)用鏈很長時,參數(shù)傳遞會很復(fù)雜,如下圖:

f1產(chǎn)生的參數(shù)b要傳給f2,雖然f2并不需要參數(shù)b,但f3需要,所以b還是得往后傳。

如果把每一步產(chǎn)生的新變量都放到Context這個大容器里,函數(shù)之間只傳遞Context,需要什么變量時直接從Context里取,如下圖:

golang Context應(yīng)用舉例

?

f2能從context里取到a和b,f4能從context里取到a、b、c、d。

package main

import (
    "context"
    "fmt"
)

func step1(ctx context.Context) context.Context {
    //根據(jù)父context創(chuàng)建子context,創(chuàng)建context時允許設(shè)置一個<key,value>對,key和value可以是任意數(shù)據(jù)類型
    child := context.WithValue(ctx, "name", "大臉貓")
    return child
}

func step2(ctx context.Context) context.Context {
    fmt.Printf("name %s\n", ctx.Value("name"))
    //子context繼承了父context里的所有key value
    child := context.WithValue(ctx, "age", 18)
    return child
}

func step3(ctx context.Context) {
    fmt.Printf("name %s\n", ctx.Value("name")) //取出key對應(yīng)的value
    fmt.Printf("age %d\n", ctx.Value("age"))
}

func main1() {
    grandpa := context.Background() //空context
    father := step1(grandpa)        //father里有一對<key,value>
    grandson := step2(father)       //grandson里有兩對<key,value>
    step3(grandson)
}

?

Timeout

在視頻?https://www.bilibili.com/video/BV1C14y127sv/?里介紹了超時實現(xiàn)的核心原理,視頻中演示的done管道可以用Context的Done()來替代,Context的Done()管道什么時候會被關(guān)系呢?2種情況:

1. 通過context.WithCancel創(chuàng)建一個context,調(diào)用cancel()時會關(guān)閉context.Done()管道。

func f1() {
    ctx, cancel := context.WithCancel(context.Background())
    go func() {
        time.Sleep(100 * time.Millisecond)
        cancel() //調(diào)用cancel,觸發(fā)Done
    }()
    select {
    case <-time.After(300 * time.Millisecond):
        fmt.Println("未超時")
    case <-ctx.Done(): //ctx.Done()是一個管道,調(diào)用了cancel()都會關(guān)閉這個管道,然后讀操作就會立即返回
        err := ctx.Err()        //如果發(fā)生Done(管道被關(guān)閉),Err返回Done的原因,可能是被Cancel了,也可能是超時了
        fmt.Println("超時:", err) //context canceled
    }
}

?

2. 通過context.WithTimeout創(chuàng)建一個context,當(dāng)超過指定的時間或者調(diào)用cancel()時會關(guān)閉context.Done()管道。

func f2() {
    ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*100) //超時后會自動調(diào)用context的Deadline,Deadline會,觸發(fā)Done
    defer cancel()
    select {
    case <-time.After(300 * time.Millisecond):
        fmt.Println("未超時")
    case <-ctx.Done(): //ctx.Done()是一個管道,context超時或者調(diào)用了cancel()都會關(guān)閉這個管道,然后讀操作就會立即返回
        err := ctx.Err()        //如果發(fā)生Done(管道被關(guān)閉),Err返回Done的原因,可能是被Cancel了,也可能是超時了
        fmt.Println("超時:", err) //context deadline exceeded
    }
}

?

Timeout的繼承問題

通過context.WithTimeout創(chuàng)建的Context,其壽命不會超過父Context的壽命。比如:

  1. 父Context設(shè)置了10號到期,5號誕生了子Context,子Context設(shè)置了100天后到期,則實際上10號的時候子Context也會到期。
  2. 父Context設(shè)置了10號到期,5號誕生了子Context,子Context設(shè)置了1天后到期,則實際上6號的時候子Context就會到期。
func inherit_timeout() {
    parent, cancel1 := context.WithTimeout(context.Background(), time.Millisecond*1000) //parent設(shè)置100ms超時
    t0 := time.Now()
    defer cancel1()

    time.Sleep(500 * time.Millisecond) //消耗掉500ms

    // child, cancel2 := context.WithTimeout(parent, time.Millisecond*1000) //parent還剩500ms,child設(shè)置了1000ms之后到期,child.Done()管道的關(guān)閉時刻以較早的為準(zhǔn),即500ms后到期
    child, cancel2 := context.WithTimeout(parent, time.Millisecond*100) //parent還剩500ms,child設(shè)置了100ms之后到期,child.Done()管道的關(guān)閉時刻以較早的為準(zhǔn),即100ms后到期
    t1 := time.Now()
    defer cancel2()

    select {
    case <-child.Done():
        t2 := time.Now()
        fmt.Println(t2.Sub(t0).Milliseconds(), t2.Sub(t1).Milliseconds())
        fmt.Println(child.Err()) //context deadline exceeded
    }
}

?

context超時在http請求中的實際應(yīng)用

定心丸來了,最后說一遍:”context在實踐中真的很有用“

客戶端發(fā)起http請求時設(shè)置了一個2秒的超時時間:

package main
import (
    "fmt"
    "io/ioutil"
    "net/http"
    "time"
)

func main() {
    client := http.Client{
        Timeout: 2 * time.Second, //小于10秒,導(dǎo)致請求超時,會觸發(fā)Server端的http.Request.Context的Done
    }
    if resp, err := client.Get("http://127.0.0.1:5678/"); err == nil {
        defer resp.Body.Close()
        fmt.Println(resp.StatusCode)
        if bs, err := ioutil.ReadAll(resp.Body); err == nil {
            fmt.Println(string(bs))
        }
    } else {
        fmt.Println(err) //Get "http://127.0.0.1:5678/": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
    }
}

?

服務(wù)端從Request里取提context,故意休息10秒鐘,同時監(jiān)聽context.Done()管道有沒有關(guān)閉。由于Request的context是2秒超時,所以服務(wù)端還沒休息夠context.Done()管道就關(guān)閉了。

package main
import (
    "fmt"
    "net/http"
    "time"
)

func welcome(w http.ResponseWriter, req *http.Request) {
    ctx := req.Context() //取得request的context
    select {
    case <-time.After(10 * time.Second): //故意慢一點,10秒后才返回結(jié)果
        fmt.Fprintf(w, "welcome")
    case <-ctx.Done(): //超時后client會撤銷請求,觸發(fā)ctx.cancel(),從而關(guān)閉Done()管道
        err := ctx.Err()            //如果發(fā)生Done(管道被關(guān)閉),Err返回Done的原因,可能是被Cancel了,也可能是超時了
        fmt.Println("server:", err) //context canceled
    }
}

func main() {
    http.HandleFunc("/", welcome)
    http.ListenAndServe(":5678", nil)
}

?

?

到了這里,關(guān)于golang Context應(yīng)用舉例的文章就介紹完了。如果您還想了解更多內(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)文章

  • 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)
  • Go語言并發(fā)之context標(biāo)準(zhǔn)庫

    Go語言并發(fā)之context標(biāo)準(zhǔn)庫

    Go中的 goroutine 之間沒有父與子的關(guān)系,也就沒有所謂子進(jìn)程退出后的通知機(jī)制,多個 goroutine 都是平行地 被調(diào)度,多個 goroutine 如何協(xié)作工作涉及通信、同步、通知和退出四個方面。 通信:chan 通道當(dāng)然是 goroutine 之間通信的基礎(chǔ),注意這里的通信主要是指程序的數(shù)據(jù)通道。

    2024年02月09日
    瀏覽(18)
  • golang 通過context設(shè)置接口請求超時時間

    下面是直接可應(yīng)用的實例:

    2024年02月10日
    瀏覽(17)
  • Golang中context包基礎(chǔ)知識詳解

    目錄 什么是context.Context? 如何構(gòu)造context.Context對象? 衍生Context方法 使用context包需要注意的點 context.Context是Golang標(biāo)準(zhǔn)庫提供的接口(context包對此接口有多種實現(xiàn)),該接口提供了四個抽象法: Deadline方法,返回context.Context被取消的時間點,也就是需要完成任務(wù)的截止時間

    2024年02月02日
    瀏覽(22)
  • 【Golang】golang中http請求的context傳遞到異步任務(wù)的坑

    【Golang】golang中http請求的context傳遞到異步任務(wù)的坑

    在golang中,context.Context可以用來用來設(shè)置截止日期、同步信號,傳遞請求相關(guān)值的結(jié)構(gòu)體。 與 goroutine 有比較密切的關(guān)系。 在web程序中,每個Request都需要開啟一個goroutine做一些事情,這些goroutine又可能會開啟其他的 goroutine去訪問后端資源,比如數(shù)據(jù)庫、RPC服務(wù)等,它們需要訪

    2024年02月08日
    瀏覽(27)
  • 本質(zhì)安全設(shè)備標(biāo)準(zhǔn)(IEC60079-11)的理解(四)

    本質(zhì)安全設(shè)備標(biāo)準(zhǔn)(IEC60079-11)的理解(四)

    IEC60079-11使用了較長的篇幅來說明設(shè)計中需要考慮到的各種間距, 這也從一定程度上說明了間距比較重要,在設(shè)計中是需要認(rèn)真考慮。 從直覺上來講,間距越大,電路越安全,因為間距比較大,不容易產(chǎn)生電弧。同時間距比較大,也易于散熱,從溫度角度來說,設(shè)備也比較安

    2024年02月15日
    瀏覽(64)
  • Golang gin middleware的編寫與使用 context.Next函數(shù)

    Golang gin middleware的編寫與使用 context.Next函數(shù)

    在web應(yīng)用服務(wù)中,完整的一個業(yè)務(wù)處理在技術(shù)上包含 客戶端操作、服務(wù)器端處理、返回處理結(jié)果給客戶端三個步驟。 在實際的業(yè)務(wù)開發(fā)和處理中,會有更負(fù)責(zé)的業(yè)務(wù)和需求場景。一個完整的系統(tǒng)可能要包含鑒權(quán)認(rèn)證、權(quán)限管理、安全檢查、日志記錄等多維度的系統(tǒng)支持。 鑒

    2024年02月09日
    瀏覽(27)
  • IRQ Handler 的使用——以USART串口接收中斷分別在標(biāo)準(zhǔn)庫與HAL庫版本下的舉例

    ?前言: 1.中斷系統(tǒng)及EXTI外部中斷知識點見我的博文: 9.中斷系統(tǒng)、EXTI外部中斷_eirq-CSDN博客 文章瀏覽閱讀301次,點贊7次,收藏6次。EXTI(Extern Interrupt)外部中斷EXTI可以監(jiān)測指定GPIO口的電平信號,當(dāng)其指定的GPIO口產(chǎn)生電平變化時,EXTI將立即向NVIC發(fā)出中斷申請,經(jīng)過NVIC裁決

    2024年02月01日
    瀏覽(21)
  • Golang標(biāo)準(zhǔn)庫——io

    原文:Golang標(biāo)準(zhǔn)庫——io io包提供了對I/O原語的基本接口。本包的基本任務(wù)是包裝這些原語已有的實現(xiàn)(如os包里的原語),使之成為共享的公共接口,這些公共接口抽象出了泛用的函數(shù)并附加了一些相關(guān)的原語的操作。 因為這些接口和原語是對底層實現(xiàn)完全不同的低水平操

    2024年02月07日
    瀏覽(18)

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

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

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包