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中semaphore(信号量)源码
Apr 03 Golang
为什么不建议在go项目中使用init()
Apr 12 Golang
Go语言中的UTF-8实现
Apr 26 Golang
go 原生http web 服务跨域restful api的写法介绍
Apr 27 Golang
go类型转换及与C的类型转换方式
May 05 Golang
解决goland 导入项目后import里的包报红问题
May 06 Golang
GoLang中生成UUID唯一标识的实现
May 08 Golang
Golang标准库syscall详解(什么是系统调用)
May 25 Golang
Go语言实现Base64、Base58编码与解码
Jul 26 Golang
使用GO语言实现Mysql数据库CURD的简单示例
Aug 07 Golang
Golang 切片(Slice)实现增删改查
Apr 22 Golang
GoFrame基于性能测试得知grpool使用场景
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 preg_match_all结合str_replace替换内容中所有img
2008/10/11 PHP
PHP 强制性文件下载功能的函数代码(任意文件格式)
2010/05/26 PHP
php/js获取客户端mac地址的实现代码
2013/07/08 PHP
php上传图片并压缩的实现方法
2015/12/22 PHP
php cookie用户登录的详解及实例代码
2017/01/03 PHP
PHP实现唤起微信支付功能
2019/02/18 PHP
Laravel定时任务的每秒执行代码
2019/10/22 PHP
laravel框架select2多选插件初始化默认选中项操作示例
2020/02/18 PHP
JavaScript实际应用:innerHTMl和确认提示的使用
2006/06/22 Javascript
javascript数组的使用
2013/03/28 Javascript
jquery弹出关闭遮罩层实例
2013/08/06 Javascript
在javascript中执行任意html代码的方法示例解读
2013/12/25 Javascript
如何实现textarea里的不同文本显示不同颜色
2014/01/20 Javascript
ExtJS4给Combobox设置列表中的默认值示例
2014/05/02 Javascript
jQuery中unbind()方法用法实例
2015/01/19 Javascript
JavaScript与ActionScript3两者的同性与差异性
2016/09/22 Javascript
JQuery实现列表中复选框全选反选功能封装(推荐)
2016/11/24 Javascript
js中常用的Math方法总结
2017/01/12 Javascript
原生node.js案例--前后台交互
2017/02/20 Javascript
javascript基于牛顿迭代法实现求浮点数的平方根【递归原理】
2017/09/28 Javascript
vue实现树形菜单效果
2018/03/19 Javascript
JavaScript使用prototype原型实现的封装继承多态示例
2018/08/31 Javascript
CountUp.js数字滚动插件使用方法详解
2019/10/17 Javascript
JS forEach跳出循环2种实现方法
2020/06/24 Javascript
python下载图片实现方法(超简单)
2017/07/21 Python
Python实现类的创建与使用方法示例
2017/07/25 Python
python中实现数组和列表读取一列的方法
2018/04/03 Python
python多线程使用方法实例详解
2019/12/30 Python
Tensorflow中k.gradients()和tf.stop_gradient()用法说明
2020/06/10 Python
工程资料员岗位职责
2014/03/10 职场文书
服务口号大全
2014/06/11 职场文书
住宿生擅自离校检讨书
2014/09/22 职场文书
商场圣诞节活动总结
2015/05/06 职场文书
家长反馈意见及建议
2015/06/03 职场文书
《和时间赛跑》读后感3篇
2019/12/16 职场文书
Win11 Dev 预览版25174.1000发布 (附更新修复内容汇总)
2022/08/05 数码科技