Golang并發(fā)編程中Context包的使用與并發(fā)控制
一、簡介
在并發(fā)編程中,任務(wù)管理和資源控制是非常重要的,而 Golang 的 context
包 為我們提供了一種優(yōu)雅的方式來傳遞取消信號和超時控制。Context
用于在多個 Goroutine 之間傳遞上下文信息,避免 Goroutine 無法按需停止而導致資源浪費。
本篇博客將詳細介紹 context
包的用法,并通過實例講解如何在超時、取消任務(wù)和多 Goroutine 協(xié)作場景中使用它。
二、Context 的基本概念
Context
是一種攜帶取消信號、截止時間(超時)和元數(shù)據(jù)的上下文對象,主要用于父 Goroutine 與子 Goroutine 的協(xié)作。它通過層級化的結(jié)構(gòu)來管理多個并發(fā)任務(wù)。
1. context 包常用函數(shù)
context.Background()
:創(chuàng)建根上下文,通常用于程序入口。context.TODO()
:占位符上下文,表示未來會替換為實際上下文。context.WithCancel(parent Context)
:創(chuàng)建帶取消功能的子上下文。context.WithTimeout(parent Context, timeout time.Duration)
:創(chuàng)建帶超時功能的子上下文。context.WithDeadline(parent Context, deadline time.Time)
:基于指定的截止時間創(chuàng)建上下文。context.WithValue(parent Context, key, value interface{})
:傳遞攜帶額外數(shù)據(jù)的上下文。
三、Context 的基本用法
1. WithCancel:取消任務(wù)的上下文
示例:使用 WithCancel
取消 Goroutine
package main import ( "context" "fmt" "time" ) func worker(ctx context.Context, id int) { for { select { case <-ctx.Done(): // 接收取消信號 fmt.Printf("Worker %d stopped\n", id) return default: fmt.Printf("Worker %d is working...\n", id) time.Sleep(time.Second) } } } func main() { ctx, cancel := context.WithCancel(context.Background()) // 創(chuàng)建可取消的上下文 for i := 1; i <= 3; i++ { go worker(ctx, i) } time.Sleep(3 * time.Second) // 模擬主 Goroutine 的其他工作 fmt.Println("Cancelling all workers...") cancel() // 發(fā)送取消信號 time.Sleep(1 * time.Second) // 等待所有 Goroutine 退出 fmt.Println("All workers stopped.") }
輸出:
Worker 1 is working...
Worker 2 is working...
Worker 3 is working...
...
Cancelling all workers...
Worker 1 stopped
Worker 2 stopped
Worker 3 stopped
All workers stopped.
解析:
context.WithCancel
創(chuàng)建的上下文可以通過調(diào)用 cancel()
發(fā)送取消信號,從而優(yōu)雅地停止所有子 Goroutine。
四、超時控制:WithTimeout 和 WithDeadline
1. 使用 WithTimeout 控制任務(wù)超時
示例:在 2 秒內(nèi)完成任務(wù),否則超時退出
package main import ( "context" "fmt" "time" ) func worker(ctx context.Context) { select { case <-time.After(3 * time.Second): // 模擬長時間任務(wù) fmt.Println("Task completed") case <-ctx.Done(): // 接收超時信號 fmt.Println("Task timed out") } } func main() { ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) // 設(shè)置 2 秒超時 defer cancel() // 確保資源釋放 go worker(ctx) time.Sleep(4 * time.Second) // 等待任務(wù)完成或超時 }
輸出:
Task timed out
解析:
- 通過
context.WithTimeout
創(chuàng)建的上下文,2 秒內(nèi)未完成任務(wù)時自動發(fā)送取消信號。 - 超時上下文可避免 Goroutine 無限期運行,幫助更好地管理資源。
2. 使用 WithDeadline 設(shè)定截止時間
WithDeadline
和 WithTimeout
類似,只是使用具體的時間點來控制超時。
五、傳遞上下文中的數(shù)據(jù):WithValue
有時,我們需要在多個 Goroutine 之間傳遞一些元數(shù)據(jù)。WithValue
允許我們將鍵值對存入上下文,并在子 Goroutine 中訪問。
示例:傳遞用戶信息
package main import ( "context" "fmt" "time" ) func greetUser(ctx context.Context) { if user, ok := ctx.Value("user").(string); ok { fmt.Printf("Hello, %s!\n", user) } else { fmt.Println("No user found.") } } func main() { ctx := context.WithValue(context.Background(), "user", "Alice") // 在上下文中存入用戶信息 go greetUser(ctx) time.Sleep(1 * time.Second) // 確保 Goroutine 執(zhí)行完畢 }
輸出:
Hello, Alice!
解析:
WithValue
允許我們?yōu)樯舷挛脑O(shè)置鍵值對,便于在多 Goroutine 間傳遞數(shù)據(jù)。
注意:
不建議用 WithValue
傳遞重要的控制信息,例如取消信號或超時。
六、Context 的應(yīng)用場景
- API 請求的超時控制:確保 HTTP 請求不會無限期等待。
- 任務(wù)取消:當用戶主動取消某個操作時,通知相關(guān)的 Goroutine 停止工作。
- 傳遞元數(shù)據(jù):例如在服務(wù)鏈路中傳遞用戶身份、請求 ID 等信息。
七、完整示例:多任務(wù)協(xié)作控制
示例:啟動多個任務(wù),隨時可取消所有任務(wù)
package main import ( "context" "fmt" "sync" "time" ) func worker(ctx context.Context, id int, wg *sync.WaitGroup) { defer wg.Done() for { select { case <-ctx.Done(): fmt.Printf("Worker %d stopped\n", id) return default: fmt.Printf("Worker %d is processing...\n", id) time.Sleep(500 * time.Millisecond) } } } func main() { var wg sync.WaitGroup ctx, cancel := context.WithCancel(context.Background()) // 創(chuàng)建上下文 for i := 1; i <= 3; i++ { wg.Add(1) go worker(ctx, i, &wg) } time.Sleep(2 * time.Second) fmt.Println("Cancelling all workers...") cancel() // 取消所有任務(wù) wg.Wait() // 等待所有任務(wù)完成 fmt.Println("All workers stopped.") }
輸出:
Worker 1 is processing...
Worker 2 is processing...
Worker 3 is processing...
...
Cancelling all workers...
Worker 1 stopped
Worker 2 stopped
Worker 3 stopped
All workers stopped.
八、小結(jié)
- Context 用于并發(fā)控制:在 Goroutine 中傳遞取消信號、超時信號或攜帶元數(shù)據(jù)。
- 超時控制與資源管理:使用
WithTimeout
和WithCancel
及時終止任務(wù),避免資源浪費。 - 多 Goroutine 協(xié)作:通過 Context 實現(xiàn)多個 Goroutine 之間的優(yōu)雅通信。
到此這篇關(guān)于Golang并發(fā)編程中Context包的使用與并發(fā)控制的文章就介紹到這了,更多相關(guān)Golang Context包使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go 語言數(shù)據(jù)結(jié)構(gòu)之雙鏈表學習教程
這篇文章主要為大家介紹了Go 語言數(shù)據(jù)結(jié)構(gòu)之雙鏈表學習教程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-08-08使用Golang的singleflight防止緩存擊穿的方法
這篇文章主要介紹了使用Golang的singleflight防止緩存擊穿的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-04-04golang 實現(xiàn)每隔幾分鐘執(zhí)行一個函數(shù)
這篇文章主要介紹了golang 實現(xiàn)每隔幾分鐘執(zhí)行一個函數(shù),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12go?zero微服務(wù)實戰(zhàn)系服務(wù)拆分
這篇文章主要為大家介紹了go?zero微服務(wù)實戰(zhàn)系服務(wù)拆分的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-06-06