Golang并發(fā)編程中Context包的使用與并發(fā)控制
一、簡介
在并發(fā)編程中,任務管理和資源控制是非常重要的,而 Golang 的 context 包 為我們提供了一種優(yōu)雅的方式來傳遞取消信號和超時控制。Context 用于在多個 Goroutine 之間傳遞上下文信息,避免 Goroutine 無法按需停止而導致資源浪費。
本篇博客將詳細介紹 context 包的用法,并通過實例講解如何在超時、取消任務和多 Goroutine 協(xié)作場景中使用它。
二、Context 的基本概念
Context 是一種攜帶取消信號、截止時間(超時)和元數(shù)據(jù)的上下文對象,主要用于父 Goroutine 與子 Goroutine 的協(xié)作。它通過層級化的結(jié)構(gòu)來管理多個并發(fā)任務。
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:取消任務的上下文
示例:使用 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 控制任務超時
示例:在 2 秒內(nèi)完成任務,否則超時退出
package main
import (
"context"
"fmt"
"time"
)
func worker(ctx context.Context) {
select {
case <-time.After(3 * time.Second): // 模擬長時間任務
fmt.Println("Task completed")
case <-ctx.Done(): // 接收超時信號
fmt.Println("Task timed out")
}
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) // 設置 2 秒超時
defer cancel() // 確保資源釋放
go worker(ctx)
time.Sleep(4 * time.Second) // 等待任務完成或超時
}
輸出:
Task timed out
解析:
- 通過
context.WithTimeout創(chuàng)建的上下文,2 秒內(nèi)未完成任務時自動發(fā)送取消信號。 - 超時上下文可避免 Goroutine 無限期運行,幫助更好地管理資源。
2. 使用 WithDeadline 設定截止時間
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置鍵值對,便于在多 Goroutine 間傳遞數(shù)據(jù)。
注意:
不建議用 WithValue 傳遞重要的控制信息,例如取消信號或超時。
六、Context 的應用場景
- API 請求的超時控制:確保 HTTP 請求不會無限期等待。
- 任務取消:當用戶主動取消某個操作時,通知相關的 Goroutine 停止工作。
- 傳遞元數(shù)據(jù):例如在服務鏈路中傳遞用戶身份、請求 ID 等信息。
七、完整示例:多任務協(xié)作控制
示例:啟動多個任務,隨時可取消所有任務
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() // 取消所有任務
wg.Wait() // 等待所有任務完成
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及時終止任務,避免資源浪費。 - 多 Goroutine 協(xié)作:通過 Context 實現(xiàn)多個 Goroutine 之間的優(yōu)雅通信。
到此這篇關于Golang并發(fā)編程中Context包的使用與并發(fā)控制的文章就介紹到這了,更多相關Golang Context包使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Go 語言數(shù)據(jù)結(jié)構(gòu)之雙鏈表學習教程
這篇文章主要為大家介紹了Go 語言數(shù)據(jù)結(jié)構(gòu)之雙鏈表學習教程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-08-08
使用Golang的singleflight防止緩存擊穿的方法
這篇文章主要介紹了使用Golang的singleflight防止緩存擊穿的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-04-04
golang 實現(xiàn)每隔幾分鐘執(zhí)行一個函數(shù)
這篇文章主要介紹了golang 實現(xiàn)每隔幾分鐘執(zhí)行一個函數(shù),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12

