V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
guonaihong
V2EX  ›  程序员

golang context 简介(4)--API 快闪

  •  
  •   guonaihong ·
    guonaihong · 2019-09-26 09:16:45 +08:00 · 1105 次点击
    这是一个创建于 1673 天前的主题,其中的信息可能已经有所发展或是发生改变。

    上会说到 context.Done()可以通知到多个 go 程的核心代码,下面会对 context 的 API 作个简单介绍

    接口原型

    type Context interface {
        // 返回 deadline 时间,如果没有设置 ok 为 false,设置为 true
        Deadline() (deadline time.Time, ok bool)
    
        // 如果 context 被取消 case ctx.Done()会立马返回
        Done() <-chan struct{}
    
        // 如果 Done 没有被关闭,返回 nil
        // 如果 Done 关闭, 会返回错误, 错误原因如下
        // context 被取消
        // 超时,context 超过截止时间
        // Err() 返回错误,对 Err 的连续调用返回同样的错误
        Err() error
    
        // 从 context 取出设置的 k/v 变量
        Value(key interface{}) interface{}
    }
    

    Deadline 函数的用法

    Deadline 函数绑定的 context 如果是 WithTimeout 和 WithDeadline 生成的,ok 变量为 true。如果是 WithCancel 生成的为 false。这点有绕。可以看下面输出

    package main
    
    import (
        "context"
        "fmt"
        "time"
    )
    
    func main() {
        // 0
        ctx, _ := context.WithCancel(context.Background())
        fmt.Println(ctx.Deadline())
    
        // 1
        ctx, _ = context.WithDeadline(context.Background(), time.Now().Add(-time.Second*60))
        fmt.Println(ctx.Deadline())
    
        // 2
        // 2 和 1 效果一样,只是设置时间方式不一样
        ctx, _ = context.WithTimeout(context.Background(), -time.Second*60)
        fmt.Println(ctx.Deadline())
    
        // 3
        ctx, _ = context.WithDeadline(context.Background(), time.Now().Add(time.Second*60))
        fmt.Println(ctx.Deadline())
    
        // 4
        // 4 和 3 效果一样,只是设置时间方式不一样
        ctx, _ = context.WithDeadline(context.Background(), time.Now().Add(time.Second*60))
        fmt.Println(ctx.Deadline())
    }
    
    /*输出
    0001-01-01 00:00:00 +0000 UTC false
    2019-09-26 08:58:43.881587978 +0800 CST m=-59.999921123 true
    2019-09-26 08:58:43.881653923 +0800 CST m=-59.999855199 true
    2019-09-26 09:00:43.881670028 +0800 CST m=+60.000160905 true
    
    */
    

    Done 函数

    context 控制退出的核心函数。标准库引入 context 虽然褒贬不一,从个人角度来讲觉得挺好,让 case 业务的 chan 都是可取消的,统一了风格。

    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()
    select {
        case <-ctx.Done():
        // case 业务 chan
    }
    
    

    Err 函数

    如果 context 被取消,Err 返回错误,多次调用结果一样

    package main
    
    import (
        "context"
        "fmt"
    )
    
    func main() {
    
        ctx, cancel := context.WithCancel(context.Background())
        fmt.Println(ctx.Err())
        cancel()
        fmt.Println(ctx.Err())
    }
    
    /*
    输出
    <nil>
    context canceled
    
    */
    

    Value 函数

    WithValue 可以向 ctx 里面带一些值,类似 cookie 的感觉。由于不能修改原始 context,只能通过派生一个新的 ctx 携带值。 需要注意的是,context 常见用法是一个 head ctx,派生 n 多的子 ctx,为了避免全局空间污染,都会用自定义类型包装下 key 值

    
    package main
    
    import (
        "context"
        "fmt"
    )
    
    type testKey string
    
    func main() {
        // 原始 ctx
        ctx, _ := context.WithCancel(context.Background())
    
        // 派生一个新的 ctx, 里面包含一个 k,v 数据结构
        ctx = context.WithValue(ctx, testKey("mykey"), "xxxxxxxxxxx")
    
        f := func(ctx context.Context, k interface{}) {
    
            if v := ctx.Value(k); v != nil {
                fmt.Printf("value = %s\n", v)
                return
            }
            fmt.Printf("not found value, key = %s\n", k)
        }
    
        f(ctx, testKey("mykey"))
        f(ctx, "mykey")
    }
    

    我的 github

    https://github.com/guonaihong/gout

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3232 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 13:52 · PVG 21:52 · LAX 06:52 · JFK 09:52
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.