亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

重學(xué)Go語言之如何使用Context

 更新時(shí)間:2023年07月31日 11:52:12   作者:程序員讀書  
Context,中文也叫做上下文,Go語言在1.7版本中新增的context包中定義了Context,下面我們就來一起看看如何在Go語言中使用Context吧

我們知道在開發(fā)Go應(yīng)用程序時(shí),尤其是網(wǎng)絡(luò)應(yīng)用程序,需要啟動(dòng)大量的Goroutine來處理請(qǐng)求:

不過Goroutine被創(chuàng)建之后,除非執(zhí)行后正常退出或者觸發(fā)panic退出,Go并沒有提供在一個(gè)Goroutine中關(guān)閉另一個(gè)Goroutine的機(jī)制。

有沒有一種方法,可以從一個(gè)Goroutine中通知另一個(gè)Goroutine退出執(zhí)行呢?這時(shí)候就該Context登場(chǎng)了!

什么是Context

Context,中文叫做上下文,Go語言在1.7版本中新增的context包中定義了Context,Context本質(zhì)是一個(gè)接口,這個(gè)接口一共定義了四個(gè)方法:

type?Context?interface?{
?Deadline()?(deadline?time.Time,?ok?bool)
?Done()?<-chan?struct{}
?Err()?error
?Value(key?any)?any
}
  • Dateline():獲取定時(shí)關(guān)閉的時(shí)間。
  • Done():從一個(gè)channel獲取關(guān)閉的信號(hào)
  • Err():獲取錯(cuò)誤信息。
  • Value():根據(jù)keyContext取值

為什么要使用Context

為什么要使用Context?或者說設(shè)計(jì)Context的目的是什么?

想像一下這樣的場(chǎng)景,當(dāng)用戶開啟瀏覽器訪問我們的Web服務(wù)時(shí),我們可能會(huì)開啟多個(gè)Goroutine來處理用戶的請(qǐng)求,這些Goroutine需要讀取不同的資源,最終返回給用戶,但如果用戶在我們的Web服務(wù)還沒處理完成就關(guān)閉瀏覽器,斷開連接,而此時(shí)Web不知道用戶已經(jīng)關(guān)閉請(qǐng)求,仍然在處理并返回最終并不會(huì)被接收的數(shù)據(jù)。

Context設(shè)計(jì)的目的就是可以從上游的Goroutine發(fā)送信息給下游的Goroutine,回到處理用戶請(qǐng)求的場(chǎng)景,當(dāng)處理請(qǐng)求的Goroutine發(fā)現(xiàn)用戶斷開連接時(shí),通過Context發(fā)送停止執(zhí)行的信息,而下游的Goroutine得到停止信號(hào)時(shí)就返回,避免資源的浪費(fèi)。

概括起來,Context的作用主要體現(xiàn)在兩個(gè)方面:

  • Goroutine之間傳遞關(guān)閉信息,定時(shí)關(guān)閉,超時(shí)關(guān)閉,手動(dòng)關(guān)閉。
  • Goroutine之間傳遞數(shù)據(jù)。

Context的使用

下面我們來講講Context的基本使用。

創(chuàng)建Context

任何上下文都是從一個(gè)空白的Context開始的,創(chuàng)建一個(gè)空白的Context有兩種方式:

使用context.Background()

ctx?:=?context.Backgroud()

使用contenxt.TODO():

ctx?:=?context.TODO()

當(dāng)然大部分時(shí)候,我們不需要自己創(chuàng)建一個(gè)空白的Context,比如在處理HTTP請(qǐng)求時(shí):

http.HandleFunc("/hello",?func(w?http.ResponseWriter,?r?*http.Request)?{
?ctx?:=?r.Context()
})

上面的代碼中,可以從http.Request中獲取Context實(shí)例,而http.Request的實(shí)際上也是調(diào)用context.Backgroud():

//net/http/request.go
func?(r?*Request)?Context()?context.Context?{
?if?r.ctx?!=?nil?{
??return?r.ctx
?}
?return?context.Background()
}

實(shí)例講解

為了講解Context是如何在Goroutine之間傳遞信號(hào)與數(shù)據(jù),我們通過下面的案例進(jìn)行說明:

func?ReadFile(ctx?context.Context,?fileName?string,?result?chan<-?[]byte)?{
?file,?err?:=?os.Open(fileName)
?if?err?!=?nil?{
??return
?}
?totalResult?:=?make([]byte,?0)
?for?{
??select?{
??case?<-ctx.Done():
???result?<-?[]byte{}
???return
??default:
??}
??b?:=?make([]byte,?1024)
??_,?err?:=?file.Read(b)
??if?err?==?io.EOF?{
???totalResult?=?append(totalResult,?b...)
???break
??}
??totalResult?=?append(totalResult,?b...)
?}
?result?<-?totalResult
}

在上面的程序中,我們調(diào)用ContextDone()方法,該方法會(huì)返回一個(gè)Channel,而使用select語句則可以讓我們?cè)谔幚順I(yè)務(wù)的同時(shí),監(jiān)聽上游Goroutine是否有傳遞取消執(zhí)行的信息。

利用Context傳遞停止信號(hào)

空白的Context并不能發(fā)揮什么作用,要達(dá)到手動(dòng)取消執(zhí)行的目的,需要調(diào)用context包下的WithCancel函數(shù)進(jìn)行封裝,封裝返回一個(gè)新的context以及一個(gè)取消的句柄cancel函數(shù):

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

下面是完整的使用方法:

package?main
import?(
?"context"
?"fmt"
?"io"
?"os"
?"time"
)
func?main()?{
?ctx?:=?context.Background()
?ctx,?cancel?:=?context.WithCancel(ctx)
?result?:=?make(chan?[]byte)
?go?ReadFile(ctx,?"./test.tar",?result)
?time.Sleep(100?*?time.Millisecond)
?cancel()
?fmt.Println(<-result)
}

在上面的程序中,我們創(chuàng)建一個(gè)Context之后,傳給了ReadFile函數(shù),并且在暫停100毫秒后調(diào)用cancel()函數(shù),達(dá)到手動(dòng)取消另一個(gè)Goroutine的目的。

給Context設(shè)置一個(gè)截止時(shí)間

除了手動(dòng)取消,也可以調(diào)用context包下的WithDeadline()函數(shù)給Context加一個(gè)截止時(shí)間,這樣在某個(gè)時(shí)間點(diǎn),Context會(huì)自動(dòng)發(fā)出取消信號(hào):

afterTime?:=?time.Now().Add(30?*?time.Millisecond)
ctx,?cancel?:=?context.WithDeadline(context.Background(),?afterTime)

下面是完整的示例:

package?main
import?(
?"context"
?"fmt"
?"io"
?"os"
?"time"
)
func?main()?{
?afterTime?:=?time.Now().Add(30?*?time.Millisecond)
?ctx,?cancel?:=?context.WithDeadline(context.Background(),?afterTime)
?defer?cancel()
?result?:=?make(chan?[]byte)
?go?ReadFile(ctx,?"./test.tar",?result)
?fmt.Println(<-result)
}

給Context一個(gè)超時(shí)限制

調(diào)用context包下的WithTimeout()函數(shù)可以為Context加一個(gè)超時(shí)限制,這對(duì)于我們編寫超時(shí)控制程序非常有幫助:

ctx,?cancel?:=?context.WithTimeout(context.Background(),?10*time.Millisecond)

下面是完整的調(diào)用程序:

package?main
import?(
?"context"
?"fmt"
?"io"
?"os"
?"time"
)
func?main()?{
?ctx,?cancel?:=?context.WithTimeout(context.Background(),?10*time.Millisecond)
?defer?cancel()
?result?:=?make(chan?[]byte)
?go?ReadFile(ctx,?"./test.tar",?result)
?fmt.Println(<-result)
}

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

調(diào)用context包下的WithValue()函數(shù)可以生成一個(gè)攜帶數(shù)據(jù)的Context,這個(gè)機(jī)制方便我們跟蹤一個(gè)處理流程中的Goroutine

?ctx,?cancel?:=?context.WithValue(context.Background(),?"testKey","testValue")

下游的Goroutine就可以通過ContextValue()函數(shù)來獲取上游傳遞下來的值了。

func?MyGoroutine(ctx?context.Context){
?ctx.Value("testKey")
}

使用Context的幾點(diǎn)建議

Context不要放在結(jié)構(gòu)體中,需要以參數(shù)方式傳遞。

Context作為函數(shù)參數(shù)時(shí),一般放在第一位,作為函數(shù)的第一個(gè)參數(shù)。

使用 context.Background函數(shù)生成根節(jié)點(diǎn)的Context。

Context 要傳值必要的值,不要什么都傳。

Context 是多協(xié)程安全的,可以在多個(gè)協(xié)程中使用。

小結(jié)

好了,至此,你應(yīng)該對(duì)Context有所了解了吧,總的來說,通過Context可以做到:

  • 手動(dòng)控制下游Goroutine取消執(zhí)行。
  • 定時(shí)控制下游Goroutine取消執(zhí)行。
  • 超時(shí)控制下游Goroutine取消執(zhí)行。
  • 傳遞數(shù)據(jù)給下游的Goroutine。

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

相關(guān)文章

  • Golang WebView跨平臺(tái)的桌面應(yīng)用庫的使用

    Golang WebView跨平臺(tái)的桌面應(yīng)用庫的使用

    Golang WebView是一個(gè)強(qiáng)大的桌面應(yīng)用庫,本文介紹了Golang WebView的特點(diǎn)和使用方法,并列舉示例詳細(xì)的介紹了其在實(shí)際項(xiàng)目中的應(yīng)用,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-03-03
  • golang中snappy的使用場(chǎng)合實(shí)例詳解

    golang中snappy的使用場(chǎng)合實(shí)例詳解

    在java 和go語言 大字符傳達(dá)的時(shí)候, 采用snappy 壓縮 解壓縮是最好的方案。下面這篇文章主要給大家介紹了關(guān)于golang中snappy使用場(chǎng)合的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下。
    2017-12-12
  • Go語言實(shí)現(xiàn)類似c++中的多態(tài)功能實(shí)例

    Go語言實(shí)現(xiàn)類似c++中的多態(tài)功能實(shí)例

    Go本身不具有多態(tài)的特性,不能夠像Java、C++那樣編寫多態(tài)類、多態(tài)方法。但是,使用Go可以編寫具有多態(tài)功能的類綁定的方法。下面來一起看看吧
    2016-09-09
  • golang 對(duì)私有函數(shù)進(jìn)行單元測(cè)試的實(shí)例

    golang 對(duì)私有函數(shù)進(jìn)行單元測(cè)試的實(shí)例

    這篇文章主要介紹了golang 對(duì)私有函數(shù)進(jìn)行單元測(cè)試的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-05-05
  • Go使用Viper庫讀取YAML配置文件的示例代碼

    Go使用Viper庫讀取YAML配置文件的示例代碼

    Viper是適用于Go應(yīng)用程序的完整配置解決方案,它被設(shè)計(jì)用于在應(yīng)用程序中工作,并且可以處理所有類型的配置需求和格式,本文給大家介紹了Go使用Viper庫讀取YAML配置文件的方法,需要的朋友可以參考下
    2024-05-05
  • 解決Go中攔截HTTP流數(shù)據(jù)時(shí)字段丟失的問題

    解決Go中攔截HTTP流數(shù)據(jù)時(shí)字段丟失的問題

    在開發(fā)高并發(fā)的Web應(yīng)用時(shí),尤其是在處理HTTP代理和流數(shù)據(jù)攔截的場(chǎng)景下,遇到數(shù)據(jù)丟失的問題并不罕見,最近,在一個(gè)項(xiàng)目中,我遇到了一個(gè)棘手的問題:在攔截并轉(zhuǎn)發(fā)HTTP流數(shù)據(jù)的過程中,某些數(shù)據(jù)字段因?yàn)樘幚磉^快而被丟失,所以本文給大家介紹如何解決這個(gè)問題
    2024-08-08
  • GoLand利用plantuml生成UML類圖

    GoLand利用plantuml生成UML類圖

    本文主要介紹了GoLand利用plantuml生成UML類圖,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • 詳解Golang中創(chuàng)建error的方式總結(jié)與應(yīng)用場(chǎng)景

    詳解Golang中創(chuàng)建error的方式總結(jié)與應(yīng)用場(chǎng)景

    Golang中創(chuàng)建error的方式包括errors.New、fmt.Errorf、自定義實(shí)現(xiàn)了error接口的類型等,本文主要為大家介紹了這些方式的具體應(yīng)用場(chǎng)景,需要的可以參考一下
    2023-07-07
  • Golang的strings.Split()踩坑記錄

    Golang的strings.Split()踩坑記錄

    工作中,當(dāng)我們需要對(duì)字符串按照某個(gè)字符串切分成字符串?dāng)?shù)組數(shù)時(shí),常用到strings.Split(),本文主要介紹了Golang的strings.Split()踩坑記錄,感興趣的可以了解一下
    2022-05-05
  • Golang流程控制語句的具體使用

    Golang流程控制語句的具體使用

    在編寫程序時(shí),流程控制是必不可少的一部分,本文主要介紹了Golang流程控制語句的具體使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-05-05

最新評(píng)論