




版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第一文帶你深入理解GolangContext包目錄1.基本原理1.1Context包的介紹1.2Context的創(chuàng)建1.2.1WithCancel1.2.2WithDeadline1.2.3WithTimeout1.2.4WithValue2.Context的使用場(chǎng)景2.1并發(fā)控制2.2超時(shí)控制2.3數(shù)據(jù)庫(kù)連接2.4HTTP請(qǐng)求2.5gRPC請(qǐng)求3.總結(jié)
1.基本原理
1.1Context包的介紹
在Go語(yǔ)言中,Context包是用于傳遞請(qǐng)求范圍數(shù)據(jù)、取消信號(hào)和截止時(shí)間的機(jī)制。它通常被用來(lái)處理goroutine之間的通信和取消。Context包是Go語(yǔ)言內(nèi)置的,它可以很方便地使用,而不需要額外的依賴。
Context包是一個(gè)輕量級(jí)的工具,它提供了一個(gè)標(biāo)準(zhǔn)的接口,用于在goroutine之間傳遞請(qǐng)求范圍的數(shù)據(jù)、取消信號(hào)和截止時(shí)間。Context包實(shí)現(xiàn)了一種類似于樹(shù)狀結(jié)構(gòu)的數(shù)據(jù)結(jié)構(gòu),其中每個(gè)節(jié)點(diǎn)都表示一個(gè)請(qǐng)求范圍。每個(gè)節(jié)點(diǎn)都有一個(gè)唯一的key-value對(duì),其中key是一個(gè)interface{}類型的值,而value則是任何類型的值。Context包還提供了一個(gè)可選的超時(shí)機(jī)制,用于在一定時(shí)間后自動(dòng)取消請(qǐng)求。
Context包的核心是一個(gè)Context接口,它定義了一些方法,用于獲取請(qǐng)求范圍數(shù)據(jù)、取消請(qǐng)求和處理超時(shí)。
typeContextinterface{
Deadline()(deadlinetime.Time,okbool)
Done()-chanstruct{}
Err()error
Value(keyinterface{})interface{}
}
Deadline()方法返回截止時(shí)間和一個(gè)布爾值,指示截止時(shí)間是否已經(jīng)設(shè)置。Done()方法返回一個(gè)只讀的channel,當(dāng)請(qǐng)求被取消或超時(shí)時(shí),該channel將被關(guān)閉。Err()方法返回一個(gè)錯(cuò)誤,指示為什么請(qǐng)求被取消。Value()方法返回與給定key相關(guān)聯(lián)的值,如果沒(méi)有值,則返回nil。
Context包還提供了兩個(gè)用于創(chuàng)建Context的函數(shù):WithContext和Background。Background函數(shù)返回一個(gè)空的Context,而WithContext函數(shù)則根據(jù)給定的父Context創(chuàng)建一個(gè)新的Context。
Context包的基本原理是通過(guò)在goroutine之間傳遞Context來(lái)實(shí)現(xiàn)請(qǐng)求范圍數(shù)據(jù)、取消信號(hào)和截止時(shí)間的管理。當(dāng)一個(gè)goroutine創(chuàng)建了一個(gè)新的goroutine時(shí),它將Context作為參數(shù)傳遞給新的goroutine。新的goroutine可以使用這個(gè)Context來(lái)訪問(wèn)請(qǐng)求范圍數(shù)據(jù)、接收取消信號(hào)和處理超時(shí)。
1.2Context的創(chuàng)建
在Golang中,Context可以通過(guò)WithCancel、WithDeadline、WithTimeout和WithValue等函數(shù)來(lái)創(chuàng)建。下面分別介紹這些函數(shù)的用法和注意事項(xiàng)。
1.2.1WithCancel
WithCancel函數(shù)可以用于創(chuàng)建一個(gè)Context對(duì)象,并返回一個(gè)可取消的上下文和一個(gè)取消函數(shù)。當(dāng)調(diào)用取消函數(shù)時(shí),會(huì)通知所有的Context對(duì)象和其子Context對(duì)象,使它們都取消執(zhí)行。
funcWithCancel(parentContext)(ctxContext,cancelCancelFunc)
下面是一個(gè)示例代碼:
packagemain
import(
"context"
"fmt"
"time"
funcmain(){
parent:=context.Background()
ctx,cancel:=context.WithCancel(parent)
gofunc(){
select{
case-ctx.Done():
fmt.Println(ctx.Err())
return
case-time.After(5*time.Second):
fmt.Println("workdone")
}
}()
time.Sleep(10*time.Second)
cancel()
time.Sleep(1*time.Second)
}
在上面的代碼中,我們首先使用context.Background()函數(shù)創(chuàng)建一個(gè)根Context對(duì)象parent,然后使用WithCancel函數(shù)創(chuàng)建一個(gè)子Context對(duì)象ctx,并返回一個(gè)可取消的上下文和一個(gè)取消函數(shù)cancel。接下來(lái),我們?cè)谝粋€(gè)goroutine中使用select語(yǔ)句監(jiān)聽(tīng)Context對(duì)象的Done方法和time.After函數(shù)的返回值,如果Done方法返回一個(gè)非nil的error,則說(shuō)明Context已經(jīng)被取消,否則說(shuō)明time.After函數(shù)已經(jīng)超時(shí)。在主函數(shù)中,我們調(diào)用cancel函數(shù)來(lái)通知Context對(duì)象和其子Context對(duì)象,使它們都取消執(zhí)行。最后,我們使用time.Sleep函數(shù)讓程序等待一段時(shí)間,以便觀察Context的執(zhí)行情況。
1.2.2WithDeadline
WithDeadline函數(shù)可以用于創(chuàng)建一個(gè)Context對(duì)象,并返回一個(gè)截止時(shí)間和一個(gè)取消函數(shù)。當(dāng)超過(guò)截止時(shí)間時(shí),會(huì)自動(dòng)通知所有的Context對(duì)象和其子Context對(duì)象,使它們都取消執(zhí)行。
funcWithDeadline(parentContext,deadlinetime.Time)(ctxContext,cancelCancelFunc)
下面是一個(gè)示例代碼:
packagemain
import(
"context"
"fmt"
"time"
funcmain(){
parent:=context.Background()
ctx,cancel:=context.WithDeadline(parent,time.Now().Add(5*time.Second))
gofunc(){
select{
case-ctx.Done():
fmt.Println(ctx.Err())
return
case-time.After(10*time.Second):
fmt.Println("workdone")
}
}()
time.Sleep(20*time.Second)
cancel()
time.Sleep(1*time.Second)
}
在上面的代碼中,我們首先使用context.Background()函數(shù)創(chuàng)建一個(gè)根Context對(duì)象parent,然后使用WithDeadline函數(shù)創(chuàng)建一個(gè)子Context對(duì)象ctx,并返回一個(gè)截止時(shí)間和一個(gè)取消函數(shù)cancel。接下來(lái),我們?cè)谝粋€(gè)goroutine中使用select語(yǔ)句監(jiān)聽(tīng)Context對(duì)象的Done方法和time.After函數(shù)的返回值,如果Done方法返回一個(gè)非nil的error,則說(shuō)明Context已經(jīng)被取消,否則說(shuō)明time.After函數(shù)已經(jīng)超時(shí)。在主函數(shù)中,我們調(diào)用cancel函數(shù)來(lái)通知Context對(duì)象和其子Context對(duì)象,使它們都取消執(zhí)行。最后,我們使用time.Sleep函數(shù)讓程序等待一段時(shí)間,以便觀察Context的執(zhí)行情況。
1.2.3WithTimeout
WithTimeout函數(shù)可以用于創(chuàng)建一個(gè)Context對(duì)象,并返回一個(gè)超時(shí)時(shí)間和一個(gè)取消函數(shù)。當(dāng)超過(guò)超時(shí)時(shí)間時(shí),會(huì)自動(dòng)通知所有的Context對(duì)象和其子Context對(duì)象,使它們都取消執(zhí)行。
funcWithTimeout(parentContext,timeouttime.Duration)(ctxContext,cancelCancelFunc)
下面是一個(gè)示例代碼:
packagemain
import(
"context"
"fmt"
"time"
funcmain(){
parent:=context.Background()
ctx,cancel:=context.WithTimeout(parent,5*time.Second)
gofunc(){
select{
case-ctx.Done():
fmt.Println(ctx.Err())
return
case-time.After(10*time.Second):
fmt.Println("workdone")
}
}()
time.Sleep(20*time.Second)
cancel()
time.Sleep(1*time.Second)
}
在上面的代碼中,我們首先使用context.Background()函數(shù)創(chuàng)建一個(gè)根Context對(duì)象parent,然后使用WithTimeout函數(shù)創(chuàng)建一個(gè)子Context對(duì)象ctx,并返回一個(gè)超時(shí)時(shí)間和一個(gè)取消函數(shù)cancel。接下來(lái),我們?cè)谝粋€(gè)goroutine中使用select語(yǔ)句監(jiān)聽(tīng)Context對(duì)象的Done方法和time.After函數(shù)的返回值,如果Done方法返回一個(gè)非nil的error,則說(shuō)明Context已經(jīng)被取消,否則說(shuō)明time.After函數(shù)已經(jīng)超時(shí)。在主函數(shù)中,我們調(diào)用cancel函數(shù)來(lái)通知Context對(duì)象和其子Context對(duì)象,使它們都取消執(zhí)行。最后,我們使用time.Sleep函數(shù)讓程序等待一段時(shí)間,以便觀察Context的執(zhí)行情況。
1.2.4WithValue
WithValue函數(shù)可以用于創(chuàng)建一個(gè)Context對(duì)象,并返回一個(gè)包含指定值的Context對(duì)象。這個(gè)值可以是任意類型的數(shù)據(jù),可以是基本類型、結(jié)構(gòu)體或者指針等。需要注意的是,這個(gè)值只在當(dāng)前Context對(duì)象及其子Context對(duì)象中有效,對(duì)于其他Context對(duì)象來(lái)說(shuō)是不可見(jiàn)的。
funcWithValue(parentContext,keyinterface{},valinterface{})Context
下面是一個(gè)示例代碼:
packagemain
import(
"context"
"fmt"
typeuserKeystruct{}
funcmain(){
parent:=context.Background()
ctx:=context.WithValue(parent,userKey{},"admin")
gofunc(){
ifuser,ok:=ctx.Value(userKey{}).(string);ok{
fmt.Printf("useris%s\n",user)
}else{
fmt.Println("userisnotfound")
}
}()
select{}
}
在上面的代碼中,我們首先使用context.Background()函數(shù)創(chuàng)建一個(gè)根Context對(duì)象parent,然后使用WithValue函數(shù)創(chuàng)建一個(gè)子Context對(duì)象ctx,并返回一個(gè)包含指定值的Context對(duì)象。接下來(lái),我們?cè)谝粋€(gè)goroutine中使用ctx.Value函數(shù)獲取Context對(duì)象中的值,并判斷其類型是否為字符串類型。如果是,則輸出其值,否則輸出userisnotfound。在主函數(shù)中,我們使用select語(yǔ)句使程序一直運(yùn)行,以便觀察Context的執(zhí)行情況。
2.Context的使用場(chǎng)景
2.1并發(fā)控制
一個(gè)很典型的使用場(chǎng)景是,當(dāng)我們需要同時(shí)啟動(dòng)多個(gè)goroutine進(jìn)行任務(wù)處理時(shí),我們可以使用Context來(lái)控制這些goroutine的執(zhí)行。在每個(gè)goroutine中,我們都可以檢測(cè)Context對(duì)象是否被取消,如果是,則退出goroutine的執(zhí)行,否則繼續(xù)執(zhí)行。
下面是一個(gè)示例代碼:
packagemain
import(
"context"
"fmt"
"sync"
funcworker(ctxcontext.Context,wg*sync.WaitGroup){
deferwg.Done()
for{
select{
default:
fmt.Println("work")
case-ctx.Done():
return
}
}
funcmain(){
parent:=context.Background()
ctx,cancel:=context.WithCancel(parent)
varwgsync.WaitGroup
fori:=0;ii++{
wg.Add(1)
goworker(ctx,wg)
}
cancel()
wg.Wait()
}
在上面的代碼中,我們首先使用context.Background()函數(shù)創(chuàng)建一個(gè)根Context對(duì)象parent,然后使用WithCancel函數(shù)創(chuàng)建一個(gè)子Context對(duì)象ctx,并返回一個(gè)取消函數(shù)cancel。接下來(lái),我們使用sync.WaitGroup來(lái)等待所有的goroutine執(zhí)行完成。在主函數(shù)中,我們啟動(dòng)了三個(gè)goroutine來(lái)執(zhí)行任務(wù),同時(shí)使用cancel函數(shù)來(lái)通知這些goroutine取消執(zhí)行。最后,我們使用Wait方法等待所有的goroutine執(zhí)行完成。
2.2超時(shí)控制
另一個(gè)典型的使用場(chǎng)景是,當(dāng)我們需要對(duì)一個(gè)操作設(shè)置一個(gè)超時(shí)時(shí)間時(shí),我們可以使用Context來(lái)控制這個(gè)操作的執(zhí)行時(shí)間。在操作執(zhí)行超時(shí)時(shí),我們可以通知Context對(duì)象和其子Context對(duì)象取消執(zhí)行。
下面是一個(gè)示例代碼:
packagemain
import(
"context"
"fmt"
"time"
funcwork(ctxcontext.Context){
for{
select{
default:
fmt.Println("work")
case-ctx.Done():
fmt.Println("workdone")
return
}
}
funcmain(){
parent:=context.Background()
ctx,cancel:=context.WithTimeout(parent,time.Second*5)
defercancel()
work(ctx)
}
在上面的代碼中,我們首先使用context.Background()函數(shù)創(chuàng)建一個(gè)根Context對(duì)象parent,然后使用WithTimeout函數(shù)創(chuàng)建一個(gè)子Context對(duì)象ctx,并返回一個(gè)取消函數(shù)cancel。在work函數(shù)中,我們啟動(dòng)一個(gè)無(wú)限循環(huán),不斷輸出work。同時(shí),我們使用select語(yǔ)句來(lái)等待Context對(duì)象被取消。在主函數(shù)中,我們使用defer語(yǔ)句調(diào)用cancel函數(shù),以確保Context對(duì)象被取消。由于我們?cè)赪ithTimeout函數(shù)中設(shè)置了一個(gè)5秒的超時(shí)時(shí)間,因此當(dāng)程序運(yùn)行超過(guò)5秒時(shí),work函數(shù)就會(huì)停止執(zhí)行。
2.3數(shù)據(jù)庫(kù)連接
在使用數(shù)據(jù)庫(kù)連接時(shí),我們通常需要保證連接池中的連接數(shù)量不會(huì)超過(guò)一定的閾值。如果連接池中的連接數(shù)量超過(guò)了閾值,則需要等待連接釋放后再進(jìn)行操作。在這種情況下,我們可以使用Context來(lái)控制連接的生命周期。
下面是一個(gè)示例代碼:
packagemain
import(
"context"
"database/sql"
"fmt"
"sync"
"time"
_"/go-sql-driver/mysql"
constmaxConn=5
funcmain(){
db,err:=sql.Open("mysql","root:root@tcp(:3306)/test")
iferr!=nil{
panic(err)
}
deferdb.Close()
ctx,cancel:=context.WithTimeout(context.Background(),time.Second*5)
defercancel()
connCh:=make(chan*sql.Conn,maxConn)
varwgsync.WaitGroup
fori:=0;imaxConn;i++{
wg.Add(1)
gofunc(){
deferwg.Done()
for{
select{
case-ctx.Done():
return
default:
iflen(connCh)maxConn{
conn,err:=db.Conn(ctx)
iferr!=nil{
fmt.Println(err)
return
}
connCh-conn
}
}
}
}()
}
wg.Wait()
}
在上面的代碼中,我們首先使用sql.Open函數(shù)打開(kāi)一個(gè)MySQL數(shù)據(jù)庫(kù)的連接,并返回一個(gè)DB對(duì)象db。接下來(lái),我們使用WithTimeout函數(shù)創(chuàng)建一個(gè)Context對(duì)象ctx,并設(shè)置一個(gè)超時(shí)時(shí)間為5秒。同時(shí),我們創(chuàng)建一個(gè)容量為maxConn的channel對(duì)象connCh,用于存儲(chǔ)數(shù)據(jù)庫(kù)連接。在goroutine中,我們使用select語(yǔ)句等待Context對(duì)象被取消。在每次循環(huán)中,我們檢查連接池中連接的數(shù)量是否超過(guò)了閾值,如果沒(méi)有,則使用db.Conn函數(shù)從連接池中獲取一個(gè)新的連接,并將其存儲(chǔ)到connCh中。最后,我們使用sync.WaitGroup等待所有的goroutine執(zhí)行完成。
2.4HTTP請(qǐng)求
在使用HTTP請(qǐng)求時(shí),我們通常需要設(shè)置一個(gè)超時(shí)時(shí)間,以確保請(qǐng)求能夠在規(guī)定的時(shí)間內(nèi)得到響應(yīng)。在這種情況下,我們可以使用Context來(lái)控制HTTP請(qǐng)求的執(zhí)行時(shí)間。
下面是一個(gè)示例代碼:
packagemain
import(
"context"
"fmt"
"io/ioutil"
"net/http"
"time"
funcmain(){
client:=http.DefaultClient
ctx,cancel:=context.WithTimeout(context.Background(),time.Second*5)
defercancel()
req,err:=http.NewRequestWithContext(ctx,http.MethodGet,"",nil)
iferr!=nil{
fmt.Println(err)
return
}
resp,err:=client.Do(req)
iferr!=nil{
fmt.Println(err)
return
}
deferresp.Body.Close()
body,err:=ioutil.ReadAll(resp.Body)
iferr!=nil{
fmt.Println(err)
return
}
fmt.Println(string(body))
}
在上面的代碼中,我們首先使用http.DefaultClient創(chuàng)建一個(gè)HTTP客戶端對(duì)象client。接下來(lái),我們使用WithTimeout函數(shù)創(chuàng)建一個(gè)Context對(duì)象ctx,并設(shè)置一個(gè)超時(shí)時(shí)間為5秒。同時(shí),我們使用http.NewRequestWithContext函數(shù)創(chuàng)建一個(gè)HTTP請(qǐng)求對(duì)象req,并將Context對(duì)象ctx作為參數(shù)傳遞給該函數(shù)。在Do函數(shù)中,我們會(huì)自動(dòng)將Context對(duì)象ctx傳遞給HTTP請(qǐng)求,并在超時(shí)時(shí)間到達(dá)后自動(dòng)取消該請(qǐng)求。
2.5gRPC請(qǐng)求
在使用gRPC請(qǐng)求時(shí),我們通常需要設(shè)置一個(gè)超時(shí)時(shí)間,以確保請(qǐng)求能夠在規(guī)定的時(shí)間內(nèi)得到響應(yīng)。在這種情況下,我們可以使用Context來(lái)控制gRPC請(qǐng)求的執(zhí)行時(shí)間。
下面是一個(gè)示例代碼:
packagemain
import(
"context"
"fmt"
"log"
"time"
pb"/example/helloworld"
"/grpc"
const(
address
="localhost:50051"
defaultName="world"
funcmain(){
conn,err:=grpc.Dial(address,grpc.WithInsecure())
iferr!=nil{
log.Fatalf("didnotconnect:%v",err)
deferconn.Close()
c:=pb.NewGreeterClient(conn)
ctx,cancel:=context.WithTimeout(context.Background(),time.Second*5)
defercancel()
r,err:=c.SayHello(ctx,pb.HelloRequest{Name:defaultName}
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 環(huán)境采樣員技能培訓(xùn)課件
- 2025年P(guān)CB感光油墨項(xiàng)目發(fā)展計(jì)劃
- 森林火災(zāi)風(fēng)險(xiǎn)評(píng)價(jià)與防范措施考核試卷
- 名片設(shè)計(jì)排版
- 老年人日常生活能力訓(xùn)練方法考核試卷
- 數(shù)字智慧方案5488丨如何提升企業(yè)信息化管理能力
- 蔬菜種植的土壤健康與生物多樣性考核試卷
- 病房護(hù)理團(tuán)隊(duì)合作與溝通考核試卷
- 西樂(lè)器生產(chǎn)中的質(zhì)量管理體系考核試卷
- 2024年工地開(kāi)復(fù)工肺炎疫情防疫方案
- 《光電顯示技術(shù)》OLED原理
- 2022年重慶江津中考數(shù)學(xué)試題及答案(A卷)
- 反恐安全政策
- 創(chuàng)新教學(xué)任務(wù)
- 淺談膿毒血癥的集束化治療及護(hù)理-PPT課件
- 新部編版《道德與法治》五年級(jí)下冊(cè)第7課《不甘屈辱 奮勇抗?fàn)帯穬?yōu)質(zhì)課件(含視頻)
- 架子工班組承包協(xié)議
- 化驗(yàn)室化學(xué)試劑臺(tái)賬范例
- 楊家灣220KV變電站工程預(yù)算表
- 第七課:構(gòu)圖的形式
- 六類網(wǎng)線檢測(cè)報(bào)告(共9頁(yè))
評(píng)論
0/150
提交評(píng)論