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语言使用select{}阻塞main函数介绍
Apr 25 Golang
golang日志包logger的用法详解
May 05 Golang
浅谈golang package中init方法的多处定义及运行顺序问题
May 06 Golang
关于golang高并发的实现与注意事项说明
May 08 Golang
go语言基础 seek光标位置os包的使用
May 09 Golang
Golang二维数组的使用方式
May 28 Golang
Go 语言结构实例分析
Jul 04 Golang
Golang并发操作中常见的读写锁详析
Aug 30 Golang
Go语言基础map用法及示例详解
Nov 17 Golang
Golang 并发下的问题定位及解决方案
Mar 16 Golang
golang三种设计模式之简单工厂、方法工厂和抽象工厂
Apr 10 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调用mysql存储过程
2007/02/14 PHP
POSIX 风格和兼容 Perl 风格两种正则表达式主要函数的类比(preg_match, preg_replace, ereg, ereg_replace)
2010/10/12 PHP
php计算十二星座的函数代码
2012/08/21 PHP
PHP中多线程的两个实现方法
2016/10/14 PHP
Thinkphp5框架ajax接口实现方法分析
2019/08/28 PHP
深入理解JavaScript系列(15) 函数(Functions)
2012/04/12 Javascript
jQuery 回车事件enter使用示例
2014/02/18 Javascript
js用typeof方法判断undefined类型
2014/07/15 Javascript
使用jquery+CSS3实现仿windows10开始菜单的下拉导航菜单特效
2015/09/24 Javascript
JS+CSS实现分类动态选择及移动功能效果代码
2015/10/19 Javascript
jquery+json实现数据二级联动的方法
2015/11/28 Javascript
NodeJS远程代码执行
2016/08/28 NodeJs
使用Vue.js创建一个时间跟踪的单页应用
2016/11/28 Javascript
JavaScript错误处理和堆栈追踪详解
2017/04/18 Javascript
Bootstrap Table使用整理(一)
2017/06/09 Javascript
vue.js源代码core scedule.js学习笔记
2017/07/03 Javascript
Array数组对象中的forEach、map、filter及reduce详析
2018/08/02 Javascript
layui 监听表格复选框选中值的方法
2018/08/15 Javascript
vue 解除鼠标的监听事件的方法
2019/11/13 Javascript
js实现数字滚动特效
2019/12/16 Javascript
卸载vue2.0并升级vue_cli3.0的实例讲解
2020/02/16 Javascript
vue使用transition组件动画效果的实例代码
2021/01/28 Vue.js
[50:05]VGJ.S vs OG 2018国际邀请赛淘汰赛BO3 第二场 8.22
2018/08/23 DOTA
Python中Selenium模拟JQuery滑动解锁实例
2017/07/26 Python
为什么称python为胶水语言
2020/06/16 Python
Html5插件教程之添加浏览器放大镜效果的商品橱窗
2016/01/07 HTML / CSS
5分钟实现Canvas鼠标跟随动画背景
2019/11/18 HTML / CSS
AmazeUI折叠式卡片布局,整合内容列表、表格组件实现
2020/08/20 HTML / CSS
YesBabyOnline美国:全球性的在线婚纱礼服工厂
2018/05/05 全球购物
美国购物网站:Clickhere2shop
2021/01/28 全球购物
求高于平均分的学生学号及成绩
2016/09/01 面试题
写出程序把一个链表中的接点顺序倒排
2014/04/28 面试题
预备党员思想汇报
2014/01/08 职场文书
2015教师年度考核评语
2015/03/25 职场文书
婚礼嘉宾致辞
2015/07/28 职场文书
MySQL窗口函数的具体使用
2021/11/17 MySQL