Golang并發(fā)編程中Context包的使用與并發(fā)控制
一、簡(jiǎn)介
在并發(fā)編程中,任務(wù)管理和資源控制是非常重要的,而 Golang 的 context 包 為我們提供了一種優(yōu)雅的方式來(lái)傳遞取消信號(hào)和超時(shí)控制。Context 用于在多個(gè) Goroutine 之間傳遞上下文信息,避免 Goroutine 無(wú)法按需停止而導(dǎo)致資源浪費(fèi)。
本篇博客將詳細(xì)介紹 context 包的用法,并通過(guò)實(shí)例講解如何在超時(shí)、取消任務(wù)和多 Goroutine 協(xié)作場(chǎng)景中使用它。
二、Context 的基本概念
Context 是一種攜帶取消信號(hào)、截止時(shí)間(超時(shí))和元數(shù)據(jù)的上下文對(duì)象,主要用于父 Goroutine 與子 Goroutine 的協(xié)作。它通過(guò)層級(jí)化的結(jié)構(gòu)來(lái)管理多個(gè)并發(fā)任務(wù)。
1. context 包常用函數(shù)
context.Background():創(chuàng)建根上下文,通常用于程序入口。context.TODO():占位符上下文,表示未來(lái)會(huì)替換為實(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(): // 接收取消信號(hào)
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ā)送取消信號(hào)
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)建的上下文可以通過(guò)調(diào)用 cancel() 發(fā)送取消信號(hào),從而優(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): // 模擬長(zhǎng)時(shí)間任務(wù)
fmt.Println("Task completed")
case <-ctx.Done(): // 接收超時(shí)信號(hào)
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
解析:
- 通過(guò)
context.WithTimeout創(chuàng)建的上下文,2 秒內(nèi)未完成任務(wù)時(shí)自動(dòng)發(fā)送取消信號(hào)。 - 超時(shí)上下文可避免 Goroutine 無(wú)限期運(yùn)行,幫助更好地管理資源。
2. 使用 WithDeadline 設(shè)定截止時(shí)間
WithDeadline 和 WithTimeout 類(lèi)似,只是使用具體的時(shí)間點(diǎn)來(lái)控制超時(shí)。
五、傳遞上下文中的數(shù)據(jù):WithValue
有時(shí),我們需要在多個(gè) Goroutine 之間傳遞一些元數(shù)據(jù)。WithValue 允許我們將鍵值對(duì)存入上下文,并在子 Goroutine 中訪問(wèn)。
示例:傳遞用戶信息
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è)置鍵值對(duì),便于在多 Goroutine 間傳遞數(shù)據(jù)。
注意:
不建議用 WithValue 傳遞重要的控制信息,例如取消信號(hào)或超時(shí)。
六、Context 的應(yīng)用場(chǎng)景
- API 請(qǐng)求的超時(shí)控制:確保 HTTP 請(qǐng)求不會(huì)無(wú)限期等待。
- 任務(wù)取消:當(dāng)用戶主動(dòng)取消某個(gè)操作時(shí),通知相關(guān)的 Goroutine 停止工作。
- 傳遞元數(shù)據(jù):例如在服務(wù)鏈路中傳遞用戶身份、請(qǐng)求 ID 等信息。
七、完整示例:多任務(wù)協(xié)作控制
示例:?jiǎn)?dòng)多個(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 中傳遞取消信號(hào)、超時(shí)信號(hào)或攜帶元數(shù)據(jù)。
- 超時(shí)控制與資源管理:使用
WithTimeout和WithCancel及時(shí)終止任務(wù),避免資源浪費(fèi)。 - 多 Goroutine 協(xié)作:通過(guò) Context 實(shí)現(xiàn)多個(gè) Goroutine 之間的優(yōu)雅通信。
到此這篇關(guān)于Golang并發(fā)編程中Context包的使用與并發(fā)控制的文章就介紹到這了,更多相關(guān)Golang Context包使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
GoLang的sync.WaitGroup與sync.Once簡(jiǎn)單使用講解
sync.WaitGroup類(lèi)型,它比通道更加適合實(shí)現(xiàn)這種一對(duì)多的goroutine協(xié)作流程。WaitGroup是開(kāi)箱即用的,也是并發(fā)安全的。同時(shí),與之前提到的同步工具一樣,它一旦被真正的使用就不能被復(fù)制了2023-01-01
Golang Http請(qǐng)求返回結(jié)果處理
本文主要介紹了Golang Http請(qǐng)求返回結(jié)果處理,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08
go語(yǔ)言Timer計(jì)時(shí)器的用法示例詳解
Go語(yǔ)言的標(biāo)準(zhǔn)庫(kù)里提供兩種類(lèi)型的計(jì)時(shí)器Timer和Ticker。這篇文章通過(guò)實(shí)例代碼給大家介紹go語(yǔ)言Timer計(jì)時(shí)器的用法,代碼簡(jiǎn)單易懂,感興趣的朋友跟隨小編一起看看吧2020-05-05
Go語(yǔ)言并發(fā)之通知退出機(jī)制的實(shí)現(xiàn)
本文主要介紹了Go語(yǔ)言并發(fā)之通知退出機(jī)制的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2025-07-07
Go語(yǔ)言簡(jiǎn)易圖像驗(yàn)證碼生成的實(shí)戰(zhàn)案例
本篇我們將使用Go語(yǔ)言結(jié)合第三方庫(kù) github.com/mojocn/base64Captcha,快速實(shí)現(xiàn)一個(gè)簡(jiǎn)易圖像驗(yàn)證碼生成接口,具有一定的參考價(jià)值,感興趣的可以了解一下2025-08-08
Golang 實(shí)現(xiàn) Redis系列(六)如何實(shí)現(xiàn) pipeline 模式的 redis 客戶端
pipeline 模式的 redis 客戶端需要有兩個(gè)后臺(tái)協(xié)程負(fù)責(zé) tcp 通信,調(diào)用方通過(guò) channel 向后臺(tái)協(xié)程發(fā)送指令,并阻塞等待直到收到響應(yīng),本文是使用 golang 實(shí)現(xiàn) redis 系列的第六篇, 將介紹如何實(shí)現(xiàn)一個(gè) Pipeline 模式的 Redis 客戶端。2021-07-07
Go語(yǔ)言七篇入門(mén)教程四通道及Goroutine
這篇文章主要為大家介紹了Go語(yǔ)言的通道及Goroutine示例詳解,本文是Go語(yǔ)言七篇入門(mén)系列篇,有需要的朋友可以借鑒參考下,希望能夠有所幫助2021-11-11

