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中的空slice案例
Apr 27 Golang
golang在GRPC中设置client的超时时间
Apr 27 Golang
golang 实现菜单树的生成方式
Apr 28 Golang
解决golang 关于全局变量的坑
May 06 Golang
go语言中http超时引发的事故解决
Jun 02 Golang
简单聊聊Golang中defer预计算参数
Mar 25 Golang
Go归并排序算法的实现方法
Apr 06 Golang
Go获取两个时区的时间差
Apr 20 Golang
深入理解 Golang 的字符串
May 04 Golang
Golang并发工具Singleflight
May 06 Golang
Go gRPC进阶教程gRPC转换HTTP
Jun 16 Golang
Go语言编译原理之变量捕获
Aug 05 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
B2K与车机的中波PK
2021/03/02 无线电
PHP中的cookie
2006/11/26 PHP
理解PHP5中static和const关键字的区别
2007/03/19 PHP
PHP数组游标实现对数组的各种操作详解
2016/01/26 PHP
(JS实现)MapBar中坐标的加密和解密的脚本
2007/05/16 Javascript
最新的10款jQuery内容滑块插件分享
2011/09/18 Javascript
基于jquery实现状态限定编辑的代码
2012/02/11 Javascript
网页前端优化之滚动延时加载图片示例
2013/07/13 Javascript
Jquery 跨域访问 Lightswitch OData Service的方法
2013/09/11 Javascript
从js向Action传中文参数出现乱码问题的解决方法
2013/12/29 Javascript
纯css+js写的一个简单的tab标签页带样式
2014/01/28 Javascript
JQuery获取与设置HTML元素的内容或文本的实现代码
2014/06/20 Javascript
jQuery移除tr无效的解决方法(tr是动态添加)
2014/09/22 Javascript
javascript中传统事件与现代事件
2015/06/23 Javascript
Javascrip实现文字跳动特效
2016/11/27 Javascript
angularjs实现的前端分页控件示例
2017/02/10 Javascript
基于HTML5+JS实现本地图片裁剪并上传功能
2017/03/24 Javascript
详解vue通过NGINX部署在子目录或者二级目录实践
2018/09/03 Javascript
Vue.js结合bootstrap前端实现分页和排序效果
2018/12/29 Javascript
js实现随机8位验证码
2020/07/24 Javascript
Vue实现商品分类菜单数量提示功能
2019/07/26 Javascript
JS函数进阶之prototy用法实例分析
2020/01/15 Javascript
Python实现的排列组合计算操作示例
2017/10/13 Python
在windows下Python打印彩色字体的方法
2018/05/15 Python
Python实现压缩文件夹与解压缩zip文件的方法
2018/09/01 Python
python中dir()与__dict__属性的区别浅析
2018/12/10 Python
Python实现二叉搜索树BST的方法示例
2019/07/30 Python
Python中顺序表原理与实现方法详解
2019/12/03 Python
HTML5 FormData 方法介绍以及实现文件上传示例
2017/09/12 HTML / CSS
J2EE模式面试题
2016/10/11 面试题
俄语翻译实习生的自我评价分享
2013/11/06 职场文书
大学军训感言800字
2014/02/27 职场文书
创建卫生先进单位实施方案
2014/03/10 职场文书
大学生求职计划书
2014/04/30 职场文书
2014年向国旗敬礼活动总结
2014/09/27 职场文书
OpenCV实现普通阈值
2021/11/17 Java/Android