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原生库的中bytes.Buffer用法
Apr 25 Golang
golang中的空slice案例
Apr 27 Golang
解决Golang中ResponseWriter的一个坑
Apr 27 Golang
go 原生http web 服务跨域restful api的写法介绍
Apr 27 Golang
解决Golang time.Parse和time.Format的时区问题
Apr 29 Golang
golang switch语句的灵活写法介绍
May 06 Golang
试了下Golang实现try catch的方法
Jul 01 Golang
使用GO语言实现Mysql数据库CURD的简单示例
Aug 07 Golang
Go 通过结构struct实现接口interface的问题
Oct 05 Golang
一文搞懂Golang 时间和日期相关函数
Dec 06 Golang
Go Grpc Gateway兼容HTTP协议文档自动生成网关
Jun 16 Golang
Go本地测试解耦任务拆解及沟通详解Go本地测试的思路沟通的重要性总结
Jun 21 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扩展
2010/03/12 PHP
php函数之子字符串替换&amp;#65279; str_replace
2011/03/23 PHP
PHP设计模式之代理模式的深入解析
2013/06/13 PHP
php图片处理函数获取类型及扩展名实例
2014/11/19 PHP
在Mac OS上搭建Nginx+PHP+MySQL开发环境的教程
2015/12/21 PHP
PHP开发中常用的十个代码样例
2016/02/02 PHP
学习js所必须要知道的一些
2007/03/07 Javascript
利用jquery操作select下拉列表框的代码
2010/06/04 Javascript
麻雀虽小五脏俱全 Dojo自定义控件应用
2010/09/04 Javascript
js控制的回到页面顶端goTop的代码实现
2013/03/20 Javascript
jquery ajax的success回调函数中实现按钮置灰倒计时
2013/11/19 Javascript
JS和JQUERY获取页面大小,滚动条位置,元素位置(示例代码)
2013/12/14 Javascript
js形成页面的一种遮罩效果实例代码
2014/01/04 Javascript
浅谈jquery页面初始化的4种方式
2016/11/27 Javascript
Canvas实现动态的雪花效果
2017/02/13 Javascript
vue2.0实现音乐/视频播放进度条组件
2018/06/06 Javascript
Angular5中调用第三方库及jQuery的添加的方法
2018/06/07 jQuery
webpack 样式加载的实现原理
2018/06/12 Javascript
layer ui 导入文件之前传入数据的实例
2019/09/23 Javascript
Python读写配置文件的方法
2015/06/03 Python
Python中将字典转换为列表的方法
2016/09/21 Python
Python中使用支持向量机SVM实践
2017/12/27 Python
pandas DataFrame数据转为list的方法
2018/04/11 Python
神经网络相关之基础概念的讲解
2018/12/29 Python
Python定时任务随机时间执行的实现方法
2019/08/14 Python
Python内置数据类型list各方法的性能测试过程解析
2020/01/07 Python
python中selenium库的基本使用详解
2020/07/31 Python
THE OUTNET美国官网:国际设计师品牌折扣网站
2017/03/07 全球购物
Bench加拿大官方网站:英国城市服装品牌
2017/11/03 全球购物
党校培训思想汇报
2014/01/03 职场文书
购房意向书
2014/04/01 职场文书
节约用水倡议书
2014/04/16 职场文书
五年级学生评语
2014/04/22 职场文书
2016大学生社会实践心得体会范文
2016/01/14 职场文书
Python Pandas模块实现数据的统计分析的方法
2021/06/24 Python
Vertica集成Apache Hudi重磅使用指南
2022/03/31 Servers