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 如何用反射reflect操作结构体
Apr 28 Golang
解决Go gorm踩过的坑
Apr 30 Golang
解决golang结构体tag编译错误的问题
May 02 Golang
go设置多个GOPATH的方式
May 05 Golang
解决goland 导入项目后import里的包报红问题
May 06 Golang
Golang Gob编码(gob包的使用详解)
May 07 Golang
Go语言实现一个简单的并发聊天室的项目实战
Mar 18 Golang
golang使用map实现去除重复数组
Apr 14 Golang
GO语言字符串处理函数之处理Strings包
Apr 14 Golang
Golang 链表的学习和使用
Apr 19 Golang
Golang入门之计时器
May 04 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
IIS+PHP+MySQL+Zend配置 (视频教程)
2006/12/13 PHP
php二维数组转成字符串示例
2014/02/17 PHP
CI配置多数据库访问的方法
2016/03/28 PHP
解决laravel 出现ajax请求419(unknown status)的问题
2019/09/03 PHP
javascript不同页面传值的改进版
2008/09/30 Javascript
jquery特效 幻灯片效果示例代码
2013/07/16 Javascript
基于pthread_create,readlink,getpid等函数的学习与总结
2013/07/17 Javascript
JS实现两个大数(整数)相乘
2014/04/28 Javascript
ExtJS4如何自动生成控制grid的列显示、隐藏的checkbox
2014/05/02 Javascript
js实现超酷的照片墙展示效果图附源码下载
2015/10/08 Javascript
浏览器检测JS代码(兼容目前各大主流浏览器)
2016/02/21 Javascript
JQuery中attr属性和jQuery.data()学习笔记【必看】
2016/05/18 Javascript
原生JS版和jquery版实现checkbox的全选/全不选/点选/行内点选(Mr.Think)
2016/10/29 Javascript
详解Node.js:events事件模块
2016/11/24 Javascript
在 Angular2 中实现自定义校验指令(确认密码)的方法
2017/01/23 Javascript
bootstrap实现动态进度条效果
2017/03/08 Javascript
windows下vue.js开发环境搭建教程
2017/03/20 Javascript
从零开始学习Node.js系列教程之设置HTTP头的方法示例
2017/04/13 Javascript
Angular5集成eventbus的示例代码
2018/07/19 Javascript
详解vue-property-decorator使用手册
2019/07/29 Javascript
使用Python导出Excel图表以及导出为图片的方法
2015/11/07 Python
python+requests+unittest API接口测试实例(详解)
2017/06/10 Python
Python的SimpleHTTPServer模块用处及使用方法简介
2018/01/22 Python
替换python字典中的key值方法
2018/07/06 Python
TensorFlow利用saver保存和提取参数的实例
2018/07/26 Python
python代码编写计算器小程序
2020/03/30 Python
如何基于Python实现数字类型转换
2020/02/07 Python
Scrapy基于scrapy_redis实现分布式爬虫部署的示例
2020/09/29 Python
pycharm使用技巧之自动调整代码格式总结
2020/11/04 Python
python代码实现猜拳小游戏
2020/11/30 Python
人力资源管理专业自荐书范文
2014/02/10 职场文书
领导干部作风建设总结
2014/10/23 职场文书
2015年学校教育教学工作总结
2015/04/22 职场文书
2015年办公室文员工作总结
2015/04/24 职场文书
先进个人主要事迹范文
2015/11/04 职场文书
用Python的绘图库(matplotlib)绘制小波能量谱
2021/04/17 Python