专业的编程技术博客社区

网站首页 > 博客文章 正文

Context上下文实践(什么是上下文对象)

baijin 2024-08-17 11:10:51 博客文章 9 ℃ 0 评论

使用 Context 的程序包需要遵循如下的原则来满足接口的一致性以及便于静态分析

1.不要把 Context 存在一个结构体当中, 显式地传入函数。Context 变量需要作为第一个参数使用, 一般命名为ctx

2.即使方法允许, 也不要传入一个 nil 的 Context , 如果你不确定你要用什么 Context 的时候传一个 context.TODO

3.使用 context 的 Value 相关方法只应该用于在程序和接口中传递的和请求相关的元数据, 不要用它来传递一些可选的参数

4.同样的 Context 可以用来传递到不同的 goroutine 中, Context 在多个goroutine 中是安全的

方法说明

Done 方法在Context被取消或超时时返回一个close的channel,close的channel可以作为广播通知, 告诉给context相关的函数要停止当前工作然后返回。

当一个父operation启动一个goroutine用于子operation, 这些子operation不能够取消父operation。下面描述的WithCancel函数提供一种方式可以取消新创建的Context.

Context可以安全的被多个goroutine使用。开发者可以把一个Context传递给任意多个goroutine然后cancel这个context的时候就能够通知到所有的goroutine。

Err方法返回context为什么被取消。

Deadline返回context何时会超时。

Value返回context相关的数据。

context 包已经给我们提供了两个, 一个是 Background(), 一个是 TODO(), 这两个函数都会返回一个 Context 的实例。

只是返回的这两个实例都是空 Context。BackGound是所有Context的root, 不能够被cancel。

实例1

这个例子传递一个上下文, 它有一个任意的截止期, 它告诉一个阻塞函数, 一旦它到达它, 它就应该放弃它的工作。

WithDeadline函数, 和WithCancel差不多, 它会多传递一个截止时间参数, 意味着到了这个时间点,会自动取消Context, 当然我们也可以不等到这个时候, 可以提前通过取消函数进行取消。

package main
import (
    "context"
    "fmt"
    "time"
)
func main() {
    d := time.Now().Add(50 * time.Millisecond)
    ctx, cancel := context.WithDeadline(context.Background(), d)
    defer cancel()
    select {
        case <-time.After(1 * time.Second):
        fmt.Println("overslept")
        case <-ctx.Done():
        fmt.Println(ctx.Err())
    }
}
运行结果
context deadline exceeded

实例2:

package main
import (
    "context"
    "fmt"
    "time"
)
func main() {
    d := time.Now().Add(50 * time.Second)
    ctx, cancel := context.WithDeadline(context.Background(), d)
    defer cancel()
    select {
        case <-time.After(1 * time.Second):
        fmt.Println("overslept")
        case <-ctx.Done():
        fmt.Println(ctx.Err())
    }
}
运行结果
overslept

实例3

package main
import (
"context"
"fmt"
)
func main() {
    gen := func(ctx context.Context) <-chan int {
    dst := make(chan int)
    n := 1
    go func() {
        for {
            select {
                case <-ctx.Done():
                return // returning not to leak the goroutine
                case dst <- n:
                n++
            }
            }
            }()
            return dst
    }
    ctx, cancel := context.WithCancel(context.Background())
    defer cancel() // cancel when we are finished consuming integers
    for n := range gen(ctx) {
        fmt.Println(n)
        if n == 5 {
            break
        }
		}
}
运行结果
1
2
3
4
5

实例4

package main
import (
"context"
"fmt"
)
func main() {
    type favContextKey string
    f := func(ctx context.Context, k favContextKey) {
    if v := ctx.Value(k); v != nil {
        fmt.Println("found value:", v)
        return
    }
    fmt.Println("key not found:", k)
    }
    k := favContextKey("language") //转换为字符串
    ctx := context.WithValue(context.Background(), k, "Go") //设置值
    f(ctx, k)
    f(ctx, favContextKey("color"))
}
运行结果
found value: Go
key not found: color

实例5

package main
import (
    "context"
    "fmt"
)
func main() {
    f := func(ctx context.Context, k string) {
    if v := ctx.Value(k); v != nil {
        fmt.Println("found value:", v)
        return
    }
    fmt.Println("key not found:", k)
    }
    ctx := context.WithValue(context.Background(), "language", "Go")
    f(ctx, "language")
    f(ctx, "color")
}
运行结果:
found value: Go
key not found: color

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表