Go语言的协程上下文的几个方法和用法


Posted in Golang onApril 11, 2022

go协程上下文context

golang的context 主要用来在 goroutine 之间传递上下文信息,包括:取消信号、超时时间、截止时间、k-v 等

context是golang1.17版本之后才出的特性

上下文解决的问题

  • 协程间的通信

例如web应用中,每一个请求都由一个协程去处理。当然处理处理请求的这个协程,一般我们还会起一些其他的协程,用来处理其他的业务,比如操作数据库,生份验证、文件读写等。这些协程是独立的,我们在当前的协程中无法感知到其他的协程执行的情况怎么样了。实用通道channel可以实现通讯功能

contextcontext.WithValue()本质上也是通过channel来实现通讯

  • 子协程的超时处理

同样例如web应用当中,我们主进程是一直常驻内存的。每一个请求都由一个协程去处理,在处理业务的过程中可能会起另外的协程去处理其他的业务,当子协程出现了异常或者阻塞了,无法向上一级的协程反馈信息,主协程接受不到反馈也会阻塞。上下文可以很好的解决这个问题,context可以实现子协程或子孙协程的超时退出或定时退出

上下文的几个方法和用法

context.WithCancel(context.Context)

WithCancel()方法传入一个上下文空实例,直接用context.Background()即可,返回一个上下文和一个取消函数。调用cancal()会向其他协程传递信号,收到信号后子协程就可以做关闭或其他处理

package main
​
import (
    "context"
    "fmt"
    "time"
)
func worker(ctx context.Context) {
    for {
        select {
        case <-ctx.Done():
            return
        default:
        }
        fmt.Println("worker...")
        time.Sleep(time.Second * 1)
    }
}
func main() {
    ctx, cancal := context.WithCancel(context.Background())
    go worker(ctx)
    time.Sleep(time.Second * 5)
    cancal()
    fmt.Println("over ...")
​
}

context.WithTimeout(context.Context,timeout)

定义一个会超时的上下文,实例化后倒计时就开始,到时间会自动调用cancel()函数通知子协程,也可以手动调用cancel()通知。如果子协程中还有子协程,继续使用这个上下文,当主协程发出取消信号时每一个使用了这个上下文的都会收到通知

package main
​
import (
    "context"
    "fmt"
    "time"
)
​
func worker(ctx context.Context) {
    for {
        select {
        case <-ctx.Done():
            return
        default:
        }
        fmt.Println("worker...")
        time.Sleep(time.Second * 1)
    }
}
​
func main() {
    ctx, cancal := context.WithTimeout(context.Background(), time.Second*2)
    go worker(ctx)
    time.Sleep(time.Second * 5)
    cancal()
    fmt.Println("over ...")
​
}

context.WithDeadline(context.Context,(绝对时间)timeout)

定义一个会超时的上下文,与Timeout不同在于,传入的时间是一个绝对时间。到了指定的时间会自动调用cancel()函数通知子协程,也可以手动调用cancel()通知。如果子协程中还有子协程,继续使用这个上下文,当主协程发出取消信号时每一个使用了这个上下文的都会收到通知

package main
​
import (
    "context"
    "fmt"
    "time"
)
​
func worker(ctx context.Context) {
    for {
        select {
        case <-ctx.Done():
            return
        default:
        }
        fmt.Println("worker...")
        time.Sleep(time.Second * 1)
    }
}
​
func main() {
    ctx, cancal := context.WithDeadline(context.Background(), time.Now().Add(3 * time.Second))
    go worker(ctx)
    time.Sleep(time.Second * 5)
    cancal()
    fmt.Println("over ...")
​
}

协程间的上下文通讯:context.WithValue()

先看一下这段代码

package main
​
import (
    "context"
    "fmt"
    "time"
)
​
type CTXKEY string
​
func worker(ctx context.Context) {
    // 在子协程中获取上下文信息
    num, ok := ctx.Value(CTXKEY("num")).(string)
    if !ok {
        fmt.Println("invalid trace code")
    }
    fmt.Println(num)
    for {
        select {
        case <-ctx.Done():
            return
        default:
        }
        fmt.Println("worker...")
        time.Sleep(time.Second * 1)
    }
}
​
func main() {
    ctx, cancal := context.WithDeadline(context.Background(), time.Now().Add(3*time.Second))
    // 利用上下文传一个 num = 1234567
    // 实例化一个上下文
    ctx = context.WithValue(ctx, CTXKEY("num"), "1234567")
    go worker(ctx)
    time.Sleep(time.Second * 5)
    cancal()
    fmt.Println("over ...")
}

通过上下文实现协程间的通信,如果项目大,为了避免变量的污染,原则上:上下文通信所用的key需要自定义一个类型

type traceCode string;context.WithValue(context.Context,key,value)

到此这篇关于golang的协程上下文的文章就介绍到这了,更多相关golang的协程上下文内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Golang 相关文章推荐
golang 如何通过反射创建新对象
Apr 28 Golang
golang 接口嵌套实现复用的操作
Apr 29 Golang
解决go在函数退出后子协程的退出问题
Apr 30 Golang
go web 预防跨站脚本的实现方式
Jun 11 Golang
Go语言实现Base64、Base58编码与解码
Jul 26 Golang
Go中的条件语句Switch示例详解
Aug 23 Golang
Go语言的协程上下文的几个方法和用法
Apr 11 Golang
Golang ort 中的sortInts 方法
Apr 24 Golang
Golang实现可重入锁的示例代码
May 25 Golang
Go调用Rust方法及外部函数接口前置
Jun 14 Golang
GoFrame框架数据校验之校验结果Error接口对象
Jun 21 Golang
Go语言编译原理之变量捕获
Aug 05 Golang
Golang 1.18 多模块Multi-Module工作区模式的新特性
Apr 11 #Golang
golang三种设计模式之简单工厂、方法工厂和抽象工厂
Golang原生rpc(rpc服务端源码解读)
Apr 07 #Golang
Go并发4种方法简明讲解
Go归并排序算法的实现方法
Apr 06 #Golang
golang操作rocketmq的示例代码
Apr 06 #Golang
victoriaMetrics库布隆过滤器初始化及使用详解
You might like
生成php程序的php代码
2008/04/07 PHP
php&amp;mysql 日期操作小记
2012/02/27 PHP
php curl模拟post请求和提交多维数组的示例代码
2015/11/19 PHP
学习PHP Cookie处理函数
2016/08/09 PHP
微信公众号开发之获取位置信息php代码
2018/06/13 PHP
Laravel开启跨域请求的方法
2019/10/13 PHP
Jquery乱码的一次解决过程 图解教程
2010/02/20 Javascript
关于js中window.location.href,location.href,parent.location.href,top.location.href的用法与区别
2010/10/18 Javascript
JavaScript高级程序设计 错误处理与调试学习笔记
2011/09/10 Javascript
学习vue.js中class与style绑定
2016/12/03 Javascript
详解Vue2+Echarts实现多种图表数据可视化Dashboard(附源码)
2017/03/21 Javascript
浅谈vuepress 踩坑记
2018/04/18 Javascript
微信小程序实现渐入渐出动画效果
2019/06/13 Javascript
Node.js学习之内置模块fs用法示例
2020/01/22 Javascript
JS实现页面鼠标点击出现图片特效
2020/08/19 Javascript
JavaScript实现世界各地时间显示
2020/09/07 Javascript
vue实现顶部菜单栏
2020/11/08 Javascript
Python实现查找系统盘中需要找的字符
2015/07/14 Python
Python入门学习指南分享
2018/04/11 Python
Numpy中矩阵matrix读取一列的方法及数组和矩阵的相互转换实例
2018/07/02 Python
python3学生名片管理v2.0版
2018/11/29 Python
uwsgi+nginx部署Django项目操作示例
2018/12/04 Python
python 获取微信好友列表的方法(微信web)
2019/02/21 Python
Python调用钉钉自定义机器人的实现
2020/01/03 Python
win10安装tensorflow-gpu1.8.0详细完整步骤
2020/01/20 Python
html5图片上传预览示例分享
2014/04/14 HTML / CSS
教堂婚礼主持词
2014/03/14 职场文书
聚美优品恶搞广告词
2014/03/14 职场文书
工作骂脏话检讨书
2014/10/05 职场文书
先进个人事迹材料
2014/12/29 职场文书
地方课程教学计划
2015/01/19 职场文书
2016年情人节广告语
2016/01/28 职场文书
2016年综治宣传月活动宣传标语口号
2016/03/16 职场文书
Javascript中的解构赋值语法详解
2021/04/02 Javascript
关于JavaScript轮播图的实现
2021/11/20 Javascript
MySQL实战记录之如何快速定位慢SQL
2022/03/23 MySQL