成人免费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

2021-12-15 09:00:00

GraphQL安全漏洞

2024-06-05 14:35:26

2025-05-21 08:15:00

GoAPI開發

2014-09-01 09:57:11

Go產品環境最佳語言

2020-05-25 11:14:59

代碼程序開發

2023-02-07 15:33:16

云遷移數據中心云計算

2024-12-12 09:02:35

2021-01-26 05:19:56

語言Go Context

2025-03-17 01:55:00

TCP服務迭代

2024-07-19 08:36:39

2019-11-22 15:27:07

技術漏洞管理網絡

2019-11-24 23:39:01

漏洞管理漏洞風險

2019-12-16 12:11:53

Docker容器Kubernetes
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲视频在线一区 | 亚洲一页 | 免费看黄色小视频 | 一级黄色片毛片 | 亚洲欧洲一区 | 黄色网址大全在线观看 | 狠狠ri| 精品久久1| 亚洲精品一区在线 | 日韩有码一区 | 在线免费视频一区 | 亚洲精品久久久久久久久久久久久 | 中文字幕韩在线第一页 | 国产视频一区二区 | 欧美三级成人理伦 | 久久精品亚洲精品国产欧美kt∨ | 波多野结衣中文字幕一区二区三区 | 欧美在线a| 亚洲高清久久 | 在线播放日韩 | 久久免费国产 | 久久久成人精品 | 成人午夜精品 | 偷拍第一页 | 97色在线观看免费视频 | 青青操91 | 精品久久久久久国产 | 日本黄视频在线观看 | 国产精品1区 | 日韩视频在线免费观看 | 欧美美女爱爱视频 | 欧美一区二区三区在线观看 | 欧美八区 | 精品久久久久久久久久久久久久 | 日韩av一区二区在线观看 | 久久久国产一区二区三区 | 日本a∨精品中文字幕在线 亚洲91视频 | 亚洲午夜视频在线观看 | 成人免费视频网站在线观看 | 欧美一区二区 | 九九热这里只有精品6 |