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各时间字符串使用解析
Apr 02 Golang
解决golang在import自己的包报错的问题
Apr 29 Golang
Golang 使用Map实现去重与set的功能操作
Apr 29 Golang
golang协程池模拟实现群发邮件功能
May 02 Golang
go语言中fallthrough的用法说明
May 06 Golang
解决golang 关于全局变量的坑
May 06 Golang
Go语言基础知识点介绍
Jul 04 Golang
Golang数据类型和相互转换
Apr 12 Golang
Golang并发工具Singleflight
May 06 Golang
基于Python实现西西成语接龙小助手
Aug 05 Golang
go goth封装第三方认证库示例详解
Aug 14 Golang
Go gorilla/sessions库安装使用
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下通过伪造http头破解防盗链的代码
2010/07/03 PHP
php动态生成缩略图并输出显示的方法
2015/04/20 PHP
JavaScript中各种编码解码函数的区别和注意事项
2010/08/19 Javascript
JS实现侧悬浮浮动实例代码
2013/11/29 Javascript
js动态拼接正则表达式的两种方法
2014/03/04 Javascript
JavaScript分析、压缩工具JavaScript Analyser
2014/12/31 Javascript
jQuery实现DIV层收缩展开的方法
2015/02/27 Javascript
jQuery的基本概念与高级编程
2015/05/14 Javascript
jquery简单实现网页层的展开与收缩效果
2015/08/07 Javascript
基于JS实现无缝滚动思路及代码分享
2016/06/07 Javascript
禁用backspace网页回退功能的实现代码
2016/11/15 Javascript
JS如何判断浏览器类型和详细区分IE各版本浏览器
2017/03/04 Javascript
Angular.js初始化之ng-app的自动绑定与手动绑定详解
2017/07/31 Javascript
修改vue+webpack run build的路径方法
2018/09/01 Javascript
bootstrap自定义样式之bootstrap实现侧边导航栏功能
2018/09/10 Javascript
解决Vue在封装了Axios后手动刷新页面拦截器无效的问题
2018/11/08 Javascript
微信运维交互机器人的示例代码
2018/11/12 Javascript
原生js实现trigger方法示例代码
2019/05/22 Javascript
vue ssr服务端渲染(小白解惑)
2019/11/10 Javascript
JS实现简易贪吃蛇游戏
2020/08/24 Javascript
[01:01:22]VGJ.S vs OG 2018国际邀请赛淘汰赛BO3 第一场 8.22
2018/08/23 DOTA
[01:03:22]LGD vs OG 2018国际邀请赛淘汰赛BO3 第一场 8.25
2018/08/29 DOTA
python中pandas.DataFrame排除特定行方法示例
2017/03/12 Python
Python实现mysql数据库更新表数据接口的功能
2017/11/19 Python
python sort、sort_index方法代码实例
2019/03/28 Python
PYQT5实现控制台显示功能的方法
2019/06/25 Python
HTML5表格_动力节点Java学院整理
2017/07/11 HTML / CSS
波兰数码相机及配件网上商店: Cyfrowe.pl
2017/06/19 全球购物
草莓网化妆品澳大利亚站:Strawberrynet AU
2017/12/18 全球购物
Hotels.com香港酒店网:你的自由行酒店订房专家
2018/01/22 全球购物
屈臣氏菲律宾官网:Watsons菲律宾
2020/06/30 全球购物
学生党支部先进事迹
2014/02/04 职场文书
年终晚会主持词
2014/03/25 职场文书
重阳节活动主持词
2015/07/04 职场文书
高中生军训感言
2015/08/01 职场文书
python中requests库+xpath+lxml简单使用
2021/04/29 Python