成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Go 語言 context 優秀實踐

開發 前端
本文我們介紹 context? 包的傳值、超時和取消的使用方式,context? 包的這三個功能,我們不僅可以用于跨 goroutine 的操作,而且還可以用于跨服務的操作。

?1.介紹

Go 語言在 v1.7 引入 context 包,關于它的使用方式,我們在之前的文章中已經介紹過,感興趣的讀者朋友們可以翻閱。

本文我們介紹 context 包的最佳實踐,包括傳值、超時和取消。

2.傳值

我們可以使用 context? 包的 func WithValue() 函數傳遞數據。

func main() {
ctx := context.WithValue(context.Background(), "ctxKey1", "ctxVal")
go func(ctx context.Context) {
// 讀取 ctx 的 value
data, ok := ctx.Value("ctxKey1").(string)
if ok {
fmt.Printf("sub goroutine get value from parent goroutine, val=%s\n", data)
}
}(ctx)
time.Sleep(1 * time.Second)
}

輸出結果:

sub goroutine get value from parent goroutine, val=ctxVal

閱讀上面這段代碼,我們使用 func WithValue()? 函數創建一個 context?,并且傳遞 key 為 ctxKey1 的數據。

我們知道 context? 是并發安全的,所以我們每次使用 context? 傳遞一個新數據,都需要使用 func WithValue()? 函數創建一個新的 context?,包裝一下 parent context。

傳遞多個數據

...
ctx := context.WithValue(context.Background(), "ctxKey1", "ctxVal")
ctx = context.WithValue(ctx, "ctxKey2", "ctxVal2")
ctx = context.WithValue(ctx, "ctxKey3", "ctxVal3")
...

閱讀上面這段代碼,我們可以發現,如果使用 context? 傳遞多個數據,就需要使用 func WithValue()? 創建多個 context。

雖然通過使用 func WithValue()? 創建多個 context 的方式,可以實現我們的需求,但是,它使代碼不再優雅,并且性能也會降低。

怎么解決?

針對該場景,我們可以參考 gRPC? 框架的 metadata? 包的代碼。定義一個 map?,通過傳遞 map? 類型的值,實現需要使用 context 傳遞多個數據的需求。

func main() {
ctxVal := make(map[string]string)
ctxVal["k1"] = "v1"
ctxVal["k2"] = "v2"
ctx := context.WithValue(context.Background(), "ctxKey1", ctxVal)
go func(ctx context.Context) {
// 讀取 ctx 的 value
data, ok := ctx.Value("ctxKey1").(map[string]string)
if ok {
fmt.Printf("sub goroutine get value from parent goroutine, val=%+v\n", data)
}
}(ctx)
time.Sleep(1 * time.Second)
}

輸出結果:

sub goroutine get value from parent goroutine, val=map[k1:v1 k2:v2]

修改傳遞數據

使用 context? 包的 func WithValue()? 函數傳遞的數據,不建議在傳輸過程中進行修改,如果遇到在傳輸過程中需要修改數據的場景,我們可以使用 COW 的方式處理,從而避免 data race。

func main() {
ctxVal := make(map[string]string)
ctxVal["k1"] = "v1"
ctxVal["k2"] = "v2"
ctx := context.WithValue(context.Background(), "ctxKey1", ctxVal)
go func(ctx context.Context) {
// 讀取 ctx 的 value
data, ok := ctx.Value("ctxKey1").(map[string]string)
if ok {
ctxVal := make(map[string]string)
for k, v := range data {
ctxVal[k] = v
}
ctxVal["k3"] = "v3"
ctx = context.WithValue(ctx, "ctxKey1", ctxVal)
data, ok := ctx.Value("ctxKey1").(map[string]string)
if !ok {
fmt.Printf("sub goroutine get value from parent goroutine, val=%+v\n", nil)
}
fmt.Printf("sub goroutine get value from parent goroutine, val=%+v\n", data)
}
}(ctx)
time.Sleep(1 * time.Second)
}

輸出結果:

sub goroutine get value from parent goroutine, val=map[k1:v1 k2:v2 k3:v3]

閱讀上面這段代碼,我們通過 COW?(copy on write) 方式修改 context 傳遞的數據。

3.超時

我們可以使用 context? 包的 func WithTimeout() 函數設置超時時間,從而避免請求阻塞。

func main() {
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Millisecond)
defer cancel()
select {
case <-time.After(1 * time.Second):
fmt.Println("overslept")
case <-ctx.Done():
fmt.Println(ctx.Err())
}

輸出結果:

context deadline exceeded

閱讀上面這段代碼,我們使用 func WithTimeout()? 函數創建一個 1ms? 取消的 context?,使用 select ... case ...? 讀取 ctx.Done()?,從而取消監聽該 context? 的 goroutine。

4.取消

我們可以使用 context? 包的 func WithCancel()? 函數取消操作,從而避免 goroutine 泄露。

func main() {
gen := func() <-chan int {
dst := make(chan int)
go func() {
var n int
for {
dst <- n
n++
}
}()
return dst
}
for n := range gen() {
fmt.Println(n)
if n == 5 {
break
}
}
time.Sleep(1 * time.Second)
}

輸出結果:

0
1
2
3
4
5

閱讀上面這段代碼,我們創建一個 gen()? 函數,啟動一個 goroutine? 生成整數,循環調用 gen()? 函數輸出生成的整數,當整數值為 5 時,停止循環,從輸出結果看,沒有發現問題。

但是,實際上該段代碼會導致 goroutine? 泄露,因為 gen() 函數一直在無限循環。

怎么解決?

我們可以使用 func WithCancel()? 函數創建一個 context?,作為 gen()? 函數的第一個參數,當停止循環時,同時調用 context? 的 CancelFunc? 取消 gen()? 函數啟動的 goroutine。

func main() {
gen := func(ctx context.Context) <-chan int {
dst := make(chan int)
go func() {
var n int
for {
dst <- n
n++
}
}()
return dst
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
for n := range gen(ctx) {
fmt.Println(n)
if n == 5 {
cancel()
break
}
}
time.Sleep(1 * time.Second)
}

輸出結果:

0
1
2
3
4
5

5.總結

本文我們介紹 context? 包的傳值、超時和取消的使用方式,context? 包的這三個功能,我們不僅可以用于跨 goroutine 的操作,而且還可以用于跨服務的操作。

責任編輯:武曉燕 來源: Golang語言開發棧
相關推薦

2025-05-20 08:20:00

GoGo Context上下文

2023-11-01 08:08:50

Go語言傳遞請求

2022-04-18 09:41:14

Go架構設計

2023-10-27 12:11:33

2023-11-06 08:14:51

Go語言Context

2023-09-21 22:02:22

Go語言高級特性

2025-06-20 08:19:53

2024-06-05 14:35:26

2021-12-15 09:00:00

GraphQL安全漏洞

2014-09-01 09:57:11

Go產品環境最佳語言

2025-05-21 08:15:00

GoAPI開發

2021-01-26 05:19:56

語言Go Context

2025-03-17 01:55:00

TCP服務迭代

2020-05-25 11:14:59

代碼程序開發

2023-02-07 15:33:16

云遷移數據中心云計算

2024-12-12 09:02:35

2019-11-22 15:27:07

技術漏洞管理網絡

2019-11-24 23:39:01

漏洞管理漏洞風險

2019-12-16 12:11:53

Docker容器Kubernetes

2024-04-11 10:20:57

JavaScript前端Web
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产精品一区二区三区在线 | 91福利在线观看 | 91传媒在线观看 | 国内精品免费久久久久软件老师 | 日韩国产一区二区三区 | 久久与欧美 | 午夜电影福利 | 欧美日韩亚洲在线 | 中文字幕一区二区三区四区五区 | 亚洲第一视频网 | 国产在线观看一区二区 | 国产一级片久久久 | 亚洲视频欧美视频 | 三级免费网 | 国产一二三区电影 | 99色综合| 亚洲激情第一页 | 久久99精品久久久水蜜桃 | 欧美一区二区三区的 | 久久手机在线视频 | 国产一区二区久久久 | 91精品国产91久久综合桃花 | 国产视频福利一区 | 亚洲成人天堂 | 精品久久影院 | 欧美电影在线观看网站 | 狠狠躁18三区二区一区 | 国产一区二区黑人欧美xxxx | 精品一区二区av | 天天躁日日躁狠狠躁2018小说 | 国产精品高潮呻吟久久久久 | 最新国产精品精品视频 | 97国产一区二区精品久久呦 | 亚洲成人网在线 | 爱操av| 欧美精品v国产精品v日韩精品 | 香蕉久久久久久 | 久草免费福利 | 国产精品视频区 | 午夜免费视频 | 久久久久国产一区二区三区 |