一文帶你深入理解GolangContext包_第1頁
一文帶你深入理解GolangContext包_第2頁
一文帶你深入理解GolangContext包_第3頁
一文帶你深入理解GolangContext包_第4頁
一文帶你深入理解GolangContext包_第5頁
已閱讀5頁,還剩12頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

第一文帶你深入理解GolangContext包目錄1.基本原理1.1Context包的介紹1.2Context的創(chuàng)建1.2.1WithCancel1.2.2WithDeadline1.2.3WithTimeout1.2.4WithValue2.Context的使用場景2.1并發(fā)控制2.2超時控制2.3數(shù)據(jù)庫連接2.4HTTP請求2.5gRPC請求3.總結(jié)

1.基本原理

1.1Context包的介紹

在Go語言中,Context包是用于傳遞請求范圍數(shù)據(jù)、取消信號和截止時間的機(jī)制。它通常被用來處理goroutine之間的通信和取消。Context包是Go語言內(nèi)置的,它可以很方便地使用,而不需要額外的依賴。

Context包是一個輕量級的工具,它提供了一個標(biāo)準(zhǔn)的接口,用于在goroutine之間傳遞請求范圍的數(shù)據(jù)、取消信號和截止時間。Context包實(shí)現(xiàn)了一種類似于樹狀結(jié)構(gòu)的數(shù)據(jù)結(jié)構(gòu),其中每個節(jié)點(diǎn)都表示一個請求范圍。每個節(jié)點(diǎn)都有一個唯一的key-value對,其中key是一個interface{}類型的值,而value則是任何類型的值。Context包還提供了一個可選的超時機(jī)制,用于在一定時間后自動取消請求。

Context包的核心是一個Context接口,它定義了一些方法,用于獲取請求范圍數(shù)據(jù)、取消請求和處理超時。

typeContextinterface{

Deadline()(deadlinetime.Time,okbool)

Done()-chanstruct{}

Err()error

Value(keyinterface{})interface{}

}

Deadline()方法返回截止時間和一個布爾值,指示截止時間是否已經(jīng)設(shè)置。Done()方法返回一個只讀的channel,當(dāng)請求被取消或超時時,該channel將被關(guān)閉。Err()方法返回一個錯誤,指示為什么請求被取消。Value()方法返回與給定key相關(guān)聯(lián)的值,如果沒有值,則返回nil。

Context包還提供了兩個用于創(chuàng)建Context的函數(shù):WithContext和Background。Background函數(shù)返回一個空的Context,而WithContext函數(shù)則根據(jù)給定的父Context創(chuàng)建一個新的Context。

Context包的基本原理是通過在goroutine之間傳遞Context來實(shí)現(xiàn)請求范圍數(shù)據(jù)、取消信號和截止時間的管理。當(dāng)一個goroutine創(chuàng)建了一個新的goroutine時,它將Context作為參數(shù)傳遞給新的goroutine。新的goroutine可以使用這個Context來訪問請求范圍數(shù)據(jù)、接收取消信號和處理超時。

1.2Context的創(chuàng)建

在Golang中,Context可以通過WithCancel、WithDeadline、WithTimeout和WithValue等函數(shù)來創(chuàng)建。下面分別介紹這些函數(shù)的用法和注意事項(xiàng)。

1.2.1WithCancel

WithCancel函數(shù)可以用于創(chuàng)建一個Context對象,并返回一個可取消的上下文和一個取消函數(shù)。當(dāng)調(diào)用取消函數(shù)時,會通知所有的Context對象和其子Context對象,使它們都取消執(zhí)行。

funcWithCancel(parentContext)(ctxContext,cancelCancelFunc)

下面是一個示例代碼:

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)建一個根Context對象parent,然后使用WithCancel函數(shù)創(chuàng)建一個子Context對象ctx,并返回一個可取消的上下文和一個取消函數(shù)cancel。接下來,我們在一個goroutine中使用select語句監(jiān)聽Context對象的Done方法和time.After函數(shù)的返回值,如果Done方法返回一個非nil的error,則說明Context已經(jīng)被取消,否則說明time.After函數(shù)已經(jīng)超時。在主函數(shù)中,我們調(diào)用cancel函數(shù)來通知Context對象和其子Context對象,使它們都取消執(zhí)行。最后,我們使用time.Sleep函數(shù)讓程序等待一段時間,以便觀察Context的執(zhí)行情況。

1.2.2WithDeadline

WithDeadline函數(shù)可以用于創(chuàng)建一個Context對象,并返回一個截止時間和一個取消函數(shù)。當(dāng)超過截止時間時,會自動通知所有的Context對象和其子Context對象,使它們都取消執(zhí)行。

funcWithDeadline(parentContext,deadlinetime.Time)(ctxContext,cancelCancelFunc)

下面是一個示例代碼:

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)建一個根Context對象parent,然后使用WithDeadline函數(shù)創(chuàng)建一個子Context對象ctx,并返回一個截止時間和一個取消函數(shù)cancel。接下來,我們在一個goroutine中使用select語句監(jiān)聽Context對象的Done方法和time.After函數(shù)的返回值,如果Done方法返回一個非nil的error,則說明Context已經(jīng)被取消,否則說明time.After函數(shù)已經(jīng)超時。在主函數(shù)中,我們調(diào)用cancel函數(shù)來通知Context對象和其子Context對象,使它們都取消執(zhí)行。最后,我們使用time.Sleep函數(shù)讓程序等待一段時間,以便觀察Context的執(zhí)行情況。

1.2.3WithTimeout

WithTimeout函數(shù)可以用于創(chuàng)建一個Context對象,并返回一個超時時間和一個取消函數(shù)。當(dāng)超過超時時間時,會自動通知所有的Context對象和其子Context對象,使它們都取消執(zhí)行。

funcWithTimeout(parentContext,timeouttime.Duration)(ctxContext,cancelCancelFunc)

下面是一個示例代碼:

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)建一個根Context對象parent,然后使用WithTimeout函數(shù)創(chuàng)建一個子Context對象ctx,并返回一個超時時間和一個取消函數(shù)cancel。接下來,我們在一個goroutine中使用select語句監(jiān)聽Context對象的Done方法和time.After函數(shù)的返回值,如果Done方法返回一個非nil的error,則說明Context已經(jīng)被取消,否則說明time.After函數(shù)已經(jīng)超時。在主函數(shù)中,我們調(diào)用cancel函數(shù)來通知Context對象和其子Context對象,使它們都取消執(zhí)行。最后,我們使用time.Sleep函數(shù)讓程序等待一段時間,以便觀察Context的執(zhí)行情況。

1.2.4WithValue

WithValue函數(shù)可以用于創(chuàng)建一個Context對象,并返回一個包含指定值的Context對象。這個值可以是任意類型的數(shù)據(jù),可以是基本類型、結(jié)構(gòu)體或者指針等。需要注意的是,這個值只在當(dāng)前Context對象及其子Context對象中有效,對于其他Context對象來說是不可見的。

funcWithValue(parentContext,keyinterface{},valinterface{})Context

下面是一個示例代碼:

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)建一個根Context對象parent,然后使用WithValue函數(shù)創(chuàng)建一個子Context對象ctx,并返回一個包含指定值的Context對象。接下來,我們在一個goroutine中使用ctx.Value函數(shù)獲取Context對象中的值,并判斷其類型是否為字符串類型。如果是,則輸出其值,否則輸出userisnotfound。在主函數(shù)中,我們使用select語句使程序一直運(yùn)行,以便觀察Context的執(zhí)行情況。

2.Context的使用場景

2.1并發(fā)控制

一個很典型的使用場景是,當(dāng)我們需要同時啟動多個goroutine進(jìn)行任務(wù)處理時,我們可以使用Context來控制這些goroutine的執(zhí)行。在每個goroutine中,我們都可以檢測Context對象是否被取消,如果是,則退出goroutine的執(zhí)行,否則繼續(xù)執(zhí)行。

下面是一個示例代碼:

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)建一個根Context對象parent,然后使用WithCancel函數(shù)創(chuàng)建一個子Context對象ctx,并返回一個取消函數(shù)cancel。接下來,我們使用sync.WaitGroup來等待所有的goroutine執(zhí)行完成。在主函數(shù)中,我們啟動了三個goroutine來執(zhí)行任務(wù),同時使用cancel函數(shù)來通知這些goroutine取消執(zhí)行。最后,我們使用Wait方法等待所有的goroutine執(zhí)行完成。

2.2超時控制

另一個典型的使用場景是,當(dāng)我們需要對一個操作設(shè)置一個超時時間時,我們可以使用Context來控制這個操作的執(zhí)行時間。在操作執(zhí)行超時時,我們可以通知Context對象和其子Context對象取消執(zhí)行。

下面是一個示例代碼:

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)建一個根Context對象parent,然后使用WithTimeout函數(shù)創(chuàng)建一個子Context對象ctx,并返回一個取消函數(shù)cancel。在work函數(shù)中,我們啟動一個無限循環(huán),不斷輸出work。同時,我們使用select語句來等待Context對象被取消。在主函數(shù)中,我們使用defer語句調(diào)用cancel函數(shù),以確保Context對象被取消。由于我們在WithTimeout函數(shù)中設(shè)置了一個5秒的超時時間,因此當(dāng)程序運(yùn)行超過5秒時,work函數(shù)就會停止執(zhí)行。

2.3數(shù)據(jù)庫連接

在使用數(shù)據(jù)庫連接時,我們通常需要保證連接池中的連接數(shù)量不會超過一定的閾值。如果連接池中的連接數(shù)量超過了閾值,則需要等待連接釋放后再進(jìn)行操作。在這種情況下,我們可以使用Context來控制連接的生命周期。

下面是一個示例代碼:

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ù)打開一個MySQL數(shù)據(jù)庫的連接,并返回一個DB對象db。接下來,我們使用WithTimeout函數(shù)創(chuàng)建一個Context對象ctx,并設(shè)置一個超時時間為5秒。同時,我們創(chuàng)建一個容量為maxConn的channel對象connCh,用于存儲數(shù)據(jù)庫連接。在goroutine中,我們使用select語句等待Context對象被取消。在每次循環(huán)中,我們檢查連接池中連接的數(shù)量是否超過了閾值,如果沒有,則使用db.Conn函數(shù)從連接池中獲取一個新的連接,并將其存儲到connCh中。最后,我們使用sync.WaitGroup等待所有的goroutine執(zhí)行完成。

2.4HTTP請求

在使用HTTP請求時,我們通常需要設(shè)置一個超時時間,以確保請求能夠在規(guī)定的時間內(nèi)得到響應(yīng)。在這種情況下,我們可以使用Context來控制HTTP請求的執(zhí)行時間。

下面是一個示例代碼:

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)建一個HTTP客戶端對象client。接下來,我們使用WithTimeout函數(shù)創(chuàng)建一個Context對象ctx,并設(shè)置一個超時時間為5秒。同時,我們使用http.NewRequestWithContext函數(shù)創(chuàng)建一個HTTP請求對象req,并將Context對象ctx作為參數(shù)傳遞給該函數(shù)。在Do函數(shù)中,我們會自動將Context對象ctx傳遞給HTTP請求,并在超時時間到達(dá)后自動取消該請求。

2.5gRPC請求

在使用gRPC請求時,我們通常需要設(shè)置一個超時時間,以確保請求能夠在規(guī)定的時間內(nèi)得到響應(yīng)。在這種情況下,我們可以使用Context來控制gRPC請求的執(zhí)行時間。

下面是一個示例代碼:

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. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論