什麼是 context
?
context
是 Go 標準庫中用來管理任務生命週期和跨 API 資料傳遞的工具。它的主要應用場景是在併發程式設計中,尤其是處理像 HTTP 請求這樣有超時限制或需要手動取消的任務。
為了更通俗地理解,可以把 context
想象成一個任務的「管理員」,它可以:
- 通知任務何時結束(比如超時或取消時)。
- 傳遞一些全域性資訊(比如使用者身份或配置)。
從常用例子開始
1. HTTP 請求中的超時控制
假設我們正在寫一個 HTTP 伺服器,客戶端請求要求超時 2 秒:
package main
import (
"context"
"fmt"
"net/http"
"time"
)
func handler(w http.ResponseWriter, r *http.Request) {
// 建立一個帶超時的 context,2 秒後自動取消
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel() // 確保函式結束時釋放資源
// 模擬一個耗時任務
select {
case <-time.After(3 * time.Second):
fmt.Fprintln(w, "Finished task")
case <-ctx.Done(): // 當 context 超時時,Done 會被觸發
http.Error(w, "Request timed out", http.StatusRequestTimeout)
}
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
執行邏輯:
- 如果任務完成時間超過 2 秒,
ctx.Done()
會收到取消訊號,及時停止任務,避免資源浪費。 context
幫助我們優雅地處理超時。
2. 跨 API 傳遞請求資訊
context
還能傳遞資料,比如使用者的認證資訊或請求 ID:
package main
import (
"context"
"fmt"
)
func main() {
// 建立一個帶鍵值對的 context
ctx := context.WithValue(context.Background(), "userID", 42)
// 傳遞 context 到其他函式
processRequest(ctx)
}
func processRequest(ctx context.Context) {
// 從 context 中取出資料
if userID := ctx.Value("userID"); userID != nil {
fmt.Println("Processing request for user:", userID)
} else {
fmt.Println("No user ID found")
}
}
執行邏輯:
- 主函式設定了
userID
,傳遞給processRequest
。 - 在子函式中,可以從
context
中提取出該資料,實現資訊的跨 API 共享。
context
的關鍵功能
-
取消訊號
使用context.WithCancel
來手動通知任務停止:ctx, cancel := context.WithCancel(context.Background()) go func() { time.Sleep(1 * time.Second) cancel() // 通知任務取消 }() <-ctx.Done() // 阻塞,直到取消訊號被觸發 fmt.Println("Task cancelled")
-
超時控制
使用context.WithTimeout
自動取消任務:ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() select { case <-time.After(3 * time.Second): fmt.Println("Task completed") case <-ctx.Done(): fmt.Println("Timeout:", ctx.Err()) // 輸出超時錯誤 }
-
資料傳遞
使用context.WithValue
跨 API 傳遞資料。
為什麼需要 context
?
-
解決併發中的控制問題:
在 Go 中,任務往往是透過goroutine
併發執行的,但如何優雅地終止任務?傳統方法可能需要複雜的 channel 通訊,而context
提供了一個統一的介面。 -
統一超時和取消機制:
無需手動編寫超時邏輯或全域性變數,context
內建了這些功能。 -
跨 API 共享資料:
context
可以像字典一樣儲存鍵值對,讓函式間更方便地傳遞資訊。
常用場景
-
HTTP 請求處理:
控制請求的超時、取消和資料傳遞。 -
資料庫操作:
遇到慢查詢時,設定超時或取消。 -
微服務通訊:
在分散式系統中傳遞請求 ID 或認證資訊。 -
併發任務協調:
例如多個 goroutine 需要根據同一個取消訊號停止。
總結
通俗來說,context
是 Go 語言中用來管理任務生命週期和傳遞資訊的工具,它讓我們可以更方便地實現超時控制、手動取消和跨 API 資料共享,簡化了併發程式設計中的複雜操作。