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 相关文章推荐
Go Gin实现文件上传下载的示例代码
Apr 02 Golang
go语言map与string的相互转换的实现
Apr 07 Golang
go 原生http web 服务跨域restful api的写法介绍
Apr 27 Golang
Go 实现英尺和米的简单单位换算方式
Apr 29 Golang
对Golang中的FORM相关字段理解
May 02 Golang
Golang 实现获取当前函数名称和文件行号等操作
May 08 Golang
go语言使用Casbin实现角色的权限控制
Jun 26 Golang
Go语言特点及基本数据类型使用详解
Mar 21 Golang
Golang原生rpc(rpc服务端源码解读)
Apr 07 Golang
Golang 并发编程 SingleFlight模式
Apr 26 Golang
GoFrame框架数据校验之校验结果Error接口对象
Jun 21 Golang
Go gorilla securecookie库的安装使用详解
Aug 14 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文件上传实例详解!!!
2007/01/02 PHP
ThinkPHP采用实现三级循环代码实例
2014/07/18 PHP
php中Snoopy类用法实例
2015/06/19 PHP
解读PHP中的垃圾回收机制
2015/08/10 PHP
php数据库的增删改查 php与javascript之间的交互
2017/08/31 PHP
通过PHP实现用户注册后邮箱验证激活
2020/11/10 PHP
JS 获取span标签中的值的代码 支持ie与firefox
2009/08/24 Javascript
第一个JavaScript入门基础 document.write输出
2010/02/22 Javascript
js下获得客户端操作系统的函数代码(1:vista,2:windows7,3:2000,4:xp,5:2003,6:2008)
2011/10/31 Javascript
jquery 操作DOM的基本用法分享
2012/04/05 Javascript
JS实现图片无间断滚动代码汇总
2014/07/30 Javascript
IE6 hack for js 集锦
2014/09/23 Javascript
使用jQuery实现更改默认alert框体
2015/04/13 Javascript
jQuery height()、innerHeight()、outerHeight()函数的区别详解
2016/05/23 Javascript
jquery精度计算代码 jquery指定精确小数位
2017/02/06 Javascript
在vue中使用express-mock搭建mock服务的方法
2018/11/07 Javascript
vue cli3 调用百度翻译API翻译页面的实现示例
2019/09/13 Javascript
解决layui中onchange失效以及form动态渲染失效的问题
2019/09/27 Javascript
js实现蒙版效果
2020/01/11 Javascript
[01:07]2015国际邀请赛 中国区预选赛精彩回顾
2015/06/15 DOTA
[53:52]EG vs VGJ.T 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
Python中的错误和异常处理简单操作示例【try-except用法】
2017/07/25 Python
python pygame模块编写飞机大战
2018/11/20 Python
python使用threading.Condition交替打印两个字符
2019/05/07 Python
简单了解python元组tuple相关原理
2019/12/02 Python
Uber Eats台湾:寻找附近提供送餐服务的餐厅
2018/05/07 全球购物
有影响力的品牌之家:Our Social Collective
2019/06/08 全球购物
乐高奥地利官方商店:LEGO Shop AT
2019/07/16 全球购物
Paradox London官方网站:英国新娘鞋婚礼鞋品牌
2019/08/29 全球购物
英国电信商店:BT Shop
2019/12/17 全球购物
计算机专业学生的自我评价
2013/12/15 职场文书
关于毕业的中学校园广播稿
2014/01/26 职场文书
公司出差管理制度范本
2015/08/05 职场文书
技术入股合作协议书
2016/03/21 职场文书
Css预编语言及区别详解
2021/04/25 HTML / CSS
浅谈resultMap的用法及关联结果集映射
2021/06/30 Java/Android