Golang context (上下文)是什麼

技术颜良發表於2024-04-07

Golang context (上下文)是什麼?

介紹

Context 是 golang 中十分重要的介面,用於定義 goroutine 中的上下文資訊,context 常用於以下幾種情況:

  • 資料傳遞:在多個 goroutine 中傳遞資料
  • 超時管理:透過配置超時時間,可以方便地配置協程的終止時間
  • 終止協程:透過使用 cancel() 方法,協程可以很方便地終止,可以批次管理多個協程的終止

Context 介面

// A Context carries a deadline, a cancelation signal, and other values across
// API boundaries.
//
// Context's methods may be called by multiple goroutines simultaneously.
type Context interface {

Done() <-chan struct{}

Deadline() (deadline time.Time, ok bool)

Err() error

Value(key interface{}) interface{}
}

根節點和派生節點

我們可以為 context 建立根節點和派生節點,為樹形結構,當根節點被 cancel() 或超時終止時,它的所有派生節點也會被終止,根節點的資料也會被所有派生節點共享。

圖片

建立根節點

ctx := context.Background() // 建立空白 context

ctx2 := context.TODO() // TODO 同樣是空白 context

建立派生節點

使用 context.WithXXX() 建立派生 context

package main

import (
"context"
"fmt"
)

func main() {
ctx := context.WithValue(context.Background(), "base", "baseVal")

ctx1 := context.WithValue(ctx, "ctx1", "ctx1Val")
ctx2 := context.WithValue(ctx, "ctx2", "ctx2Val")
ctx3 := context.WithValue(ctx, "ctx3", "ctx3Val")

fmt.Println(ctx)
fmt.Println(ctx1)
fmt.Println(ctx2)
fmt.Println(ctx3)
}

// 結果:
// context.Background.WithValue(type string, val baseVal)
// context.Background.WithValue(type string, val baseVal).WithValue(type string, val ctx1Val)
// context.Background.WithValue(type string, val baseVal).WithValue(type string, val ctx2Val)
// context.Background.WithValue(type string, val baseVal).WithValue(type string, val ctx3Val)

WithValue()

context.WithValue() 可以用於建立派生節點並新增鍵值資料,同時保留父級 context 所有的資料

WithDeadline() WithTimeout()

context.WithDeadline()context.WithTimeout() 可以用來建立帶有超時控制的 context

WithTimeout(1*time.Second) 等同於 WithDeadline(time.Now().Add(1*time.Second))

package main

import (
"context"
"fmt"
"time"
)

func main() {
ctx, _ := context.WithTimeout(context.Background(), 3*time.Second)

go func(ctx1 context.Context) {
for {
select {
case <-ctx1.Done():
fmt.Println("time out")
return
default:
fmt.Println("running...")
time.Sleep(time.Second)
}
}
}(ctx)

time.Sleep(5 * time.Second)
}

// 結果:
// running...
// running...
// running...
// time out

WithCancel()

使用 WithCancel() 可以建立手動終止的 context 執行 cancel() 即可手動終止

package main

import (
"context"
"fmt"
"time"
)

func main() {
ctx, cancel := context.WithCancel(context.Background())

go func(ctx1 context.Context) {
for {
select {
case <-ctx1.Done():
fmt.Println("canceled")
return
default:
fmt.Println("running...")
time.Sleep(time.Second)
}
}
}(ctx)

time.Sleep(3*time.Second)
cancel()
time.Sleep(5 * time.Second)
}

// 結果:
// running...
// running...
// running...
// canceled

圖片

圖片

面試寶典 · 目錄
上一篇Golang channel (通道) 是什麼?
閱讀原文
閱讀 284
作者已設定關注7天后才可留言

相關文章