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

