zoukankan      html  css  js  c++  java
  • context使用

    1. 概述

      go语言中goroutine之间的关联关系,缺乏维护,在erlang中有专门的机制来保障新开协程的生命周期,在go语言中,只能通过channel + select来实现,但不够直观,很绕。
      Context 通常被译作 上下文 ,它是一个比较抽象的概念,一般理解为程序单元的一个运行状态、现场、快照。上下上下则是存在上下层的传递, 上 会把内容传递给 下 。
      在Go语言中,程序单元也就指的是Goroutine。context 包不仅实现了在程序单元之间共享状态变量的方法,同时能通过简单的方法,使我们在被调用程序单元的外部,通过设置ctx变量值,将过期撤销信号传递给被调用的程序单元。

      在go服务器中(http服务器),对于每个请求的request都是在单独的goroutine中进行的,处理一个request也可能涉及多个goroutine之间的交互, 使用context可以使开发者方便地在这些goroutine里传递request相关的数据、取消goroutine的signal或截止时间

      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相关的数据。

    需要注意的就是 调用CancelFunc会取消child以及child生成的context,取出父context对这个child的引用,停止相关的计数器

    实战:

    1. context.Background 只应用在最高等级,作为所有派生 context 的根。
    2. context.TODO 应用在不确定要使用什么的地方,或者当前函数以后会更新以便使用 context。
    3. context 取消是建议性的,这些函数可能需要一些时间来清理和退出。
    4. context.Value 应该很少使用,它不应该被用来传递可选参数。这使得 API 隐式的并且可以引起错误。取而代之的是,这些值应该作为参数传递。
    5. 不要将 context 存储在结构中,要在函数中显式传递它们,最好是作为第一个参数。
    6. 永远不要传递不存在的 context 。相反,如果您不确定使用什么,使用一个 ToDo context。
    7. Context 结构没有取消方法,因为只有派生 context 的函数才可以取消 context。

    参考示例1:

    package main
    
    import (
        "context"
        "log"
        "os"
        "time"
    )
    
    var logg *log.Logger
    
    func someHandler() {
        ctx, cancel := context.WithCancel(context.Background())
        go doStuff(ctx)
    
    //10秒后取消doStuff
        time.Sleep(10 * time.Second)
        cancel()
    
    }
    
    //每1秒work一下,同时会判断ctx是否被取消了,如果是就退出
    func doStuff(ctx context.Context) {
        for {
            time.Sleep(1 * time.Second)
            select {
            case <-ctx.Done():
                logg.Printf("done")
                return
            default:
                logg.Printf("work")
            }
        }
    }
    
    func main() {
        logg = log.New(os.Stdout, "", log.Ltime)
        someHandler()
        logg.Printf("down")
            time.Sleep(10 * time.Second)
    }
    

      输出

    18:00:17 work
    18:00:18 work
    18:00:19 work
    18:00:20 work
    18:00:21 work
    18:00:22 work
    18:00:23 work
    18:00:24 work
    18:00:25 work
    18:00:26 down
    18:00:26 done
    

      参考示例2:

    package main
    
    import (
        "context"
        "log"
        "os"
        "time"
    )
    
    var logg *log.Logger
    
    func doTimeOutStuff(ctx context.Context) {
        for {
            time.Sleep(1 * time.Second)
    
            if deadline, ok := ctx.Deadline(); ok { //设置了deadl
                logg.Printf("deadline set")
                if time.Now().After(deadline) {
                    logg.Printf(ctx.Err().Error())
                    return
                }
    
            }
    
            select {
            case <-ctx.Done():
                logg.Printf("done")
                return
            default:
                logg.Printf("work")
            }
        }
    }
    
    func timeoutHandler() {
        ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
        // ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second))
        go doTimeOutStuff(ctx)
        // go doStuff(ctx)
    
        time.Sleep(10 * time.Second)
    
        cancel()
    
    }
    
    
    func main() {
        logg = log.New(os.Stdout, "", log.Ltime)
        timeoutHandler()
        logg.Printf("down")
    	time.Sleep(10 * time.Second)
    }
    

      输出:

    18:04:37 deadline set
    18:04:37 work
    18:04:38 deadline set
    18:04:38 work
    18:04:39 deadline set
    18:04:39 work
    18:04:40 deadline set
    18:04:40 work
    18:04:41 deadline set
    18:04:41 context deadline exceeded
    18:04:46 down
    

      参考链接:

    https://studygolang.com/articles/12566

    https://www.cnblogs.com/zhangboyu/p/7456606.html

    https://studygolang.com/articles/13866?fr=sidebar

  • 相关阅读:
    后期生成事件命令copy /y
    SevenZipShaper压缩类
    vs2017
    WCF路由服务
    微服务--
    各种流程图的绘画网路工具 processon
    ROC 准确率,召回率 F-measure理解(转载)
    Unix OpenCV安装
    转载:tar 解压缩命令~
    cppreference经验总结
  • 原文地址:https://www.cnblogs.com/yorkyang/p/10310593.html
Copyright © 2011-2022 走看看