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
作者已設定關注7天后才可留言