美文网首页区块链研习社我爱编程
golang学习笔记之:context

golang学习笔记之:context

作者: ccup区块链 | 来源:发表于2018-06-03 21:27 被阅读18次

context使用介绍:

对于context上下文的使用,有精力多朋友最好去阅读一下源码,源码的注释写的是真给力。这里列出常用的context用法。

Context接口

type Context interface {
    Deadline() (deadline time.Time, ok bool)
    Done() <-chan struct{}
    Err() error
    Value(key interface{}) interface{}
}

1. Deadline会返回一个超时时间,Goroutine获得了超时时间后,例如可以对某些io操作设定超时时间。

2.Done方法返回一个信道(channel),当Context被撤销或过期时,该信道是关闭的,即它是一个表示Context是否已关闭的信号。

3. 当Done信道关闭后,Err方法表明Context被撤的原因。

4. Value可以让Goroutine共享一些数据,当然获得数据是协程安全的。但使用这些数据的时候要注意同步,比如返回了一个map,而这个map的读写则要加锁。

goroutine之间会存在层层调用的关系,有点类似于树的结构,一层一层的,父节点子节点。

context.background

类似于树的根节点,它不能被取消、没有值、也没有过期时间。它常常作为处理Request的顶层context存在。


// Background returns a non-nil, empty Context. It is never canceled, has no
// values, and has no deadline. It is typically used by the main function,
// initialization, and tests, and as the top-level Context for incoming
// requests.
func Background() Context {
    return background
}



context.todo

如果你不确定你要用什么Context的时候传一个context.TODO;

// TODO returns a non-nil, empty Context. Code should use context.TODO when
// it's unclear which Context to use or it is not yet available (because the
// surrounding function has not yet been extended to accept a Context
// parameter). TODO is recognized by static analysis tools that determine
// whether Contexts are propagated correctly in a program.
func TODO() Context {
    return todo
}


context.WithValue

  • 传全局要用的东西,公用的参数就可以用上下文来使用。ctx 是go的一个规范。

  • 定位一个请求在哪个子系统出了问题?
    traceID,在日志中对此ID做一个聚合分析


func process(ctx context.Context) {
    //传递全局公共参数
    ret, ok := ctx.Value("trace_id").(string)
    if !ok {
        ret = ""
    }
    fmt.Printf("ret:%s\n", ret)

}

func main() {

    ret := context.WithValue(context.Background(), "trace_id", "sdfadfaf")
    process(ret)

}


context.WithTimeout

  • 控制goroutine超时
  • 传入的是从现在开始Context剩余的生命时长
  • 层层Goroutine根据判断cxt.Done()来结束

package main

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

func main() {
    // Pass a context with a timeout to tell a blocking function that it
    // should abandon its work after the timeout elapses.
    ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
    defer cancel()

    select {
    case <-time.After(1 * time.Second):
        fmt.Println("overslept")
    case <-ctx.Done():
        fmt.Println(ctx.Err()) // prints "context deadline exceeded"
    }

}


context.WithDeadline

  • 作用根context.timeout差不多
  • 过期时间由deadline和parent的过期时间共同决定
  • 层层Goroutine根据判断cxt.Done()来结束

context.WithCancel

  • 主动撤销Context的方法
package main

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

func test(ctx context.Context) <-chan int {
    dst := make(chan int)
    n := 1
    go func() {
        for {
            select {
            case <-ctx.Done()://触发done,然后退出
                fmt.Println("exited")
                return //结束这个goroutine
            case dst <- n:
                n++
            }
        }
    }()
    return dst
}

func test2() {
    //启动后台goroutine时,如何让goroutine退出?
    //使用context.WithCancel通知一个线程去结束,就是作为一个信号去抢占select对执行

    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()

    intChan := test(ctx)
    for n := range intChan {
        fmt.Println(n)
        if n == 5 {
            break
        }
    }
}

func main() {
    test2()
    //防止主线程结束而导致goroutine结束
    time.Sleep(3 * time.Second)
}

相关文章

网友评论

    本文标题:golang学习笔记之:context

    本文链接:https://www.haomeiwen.com/subject/tkjssftx.html