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各时间字符串使用解析
Apr 02 Golang
Golang二维切片初始化的实现
Apr 08 Golang
Go语言操作数据库及其常规操作的示例代码
Apr 21 Golang
golang 实现菜单树的生成方式
Apr 28 Golang
Go使用协程交替打印字符
Apr 29 Golang
使用Golang的channel交叉打印两个数组的操作
Apr 29 Golang
golang slice元素去重操作
Apr 30 Golang
golang gopm get -g -v 无法获取第三方库的解决方案
May 05 Golang
基于Go语言构建RESTful API服务
Jul 25 Golang
golang内置函数len的小技巧
Jul 25 Golang
Golang ort 中的sortInts 方法
Apr 24 Golang
Go Grpc Gateway兼容HTTP协议文档自动生成网关
Jun 16 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
php5.2.0内存管理改进
2007/01/22 PHP
php一行代码获取文件后缀名实例分析
2014/11/12 PHP
thinkPHP中分页用法实例分析
2015/12/26 PHP
php 5.4 全新的代码复用Trait详解
2017/01/05 PHP
利用PHP判断是否是连乘数字串的方法示例
2017/07/03 PHP
php与阿里云短信接口接入操作案例分析
2020/05/27 PHP
JavaScript开发时的五个注意事项
2007/12/08 Javascript
解决jquery .ajax 在IE下卡死问题的解决方法
2009/10/26 Javascript
SwfUpload在IE10上不出现上传按钮的解决方法
2013/06/25 Javascript
jQuery学习笔记之 Ajax操作篇(二) - 数据传递
2014/06/23 Javascript
js实现一个链接打开两个链接地址的方法
2015/05/12 Javascript
js实现仿百度风云榜可重复多次调用的TAB切换选项卡效果
2015/08/31 Javascript
浅析js的模块化编写 require.js
2016/12/07 Javascript
jQuery插件FusionCharts实现的MSBar2D图效果示例【附demo源码】
2017/03/24 jQuery
解决webpack打包速度慢的解决办法汇总
2017/07/06 Javascript
深入理解vue中的slot与slot-scope
2019/04/22 Javascript
微信小程序实现圆形进度条动画
2020/11/18 Javascript
详解vue中使用axios对同一个接口连续请求导致返回数据混乱的问题
2019/11/06 Javascript
JS实现星星海特效
2019/12/24 Javascript
[01:03:36]DOTA2-DPC中国联赛 正赛 VG vs Magma BO3 第二场 1月26日
2021/03/11 DOTA
Python的math模块中的常用数学函数整理
2016/02/04 Python
Python3控制路由器——使用requests重启极路由.py
2016/05/11 Python
Python统计一个字符串中每个字符出现了多少次的方法【字符串转换为列表再统计】
2019/05/05 Python
搞清楚 Python traceback的具体使用方法
2019/05/13 Python
Python 中的参数传递、返回值、浅拷贝、深拷贝
2019/06/25 Python
python GUI库图形界面开发之PyQt5中QWebEngineView内嵌网页与Python的数据交互传参详细方法实例
2020/02/26 Python
Python标准库json模块和pickle模块使用详解
2020/03/10 Python
win10下python3.8的PIL库安装过程
2020/06/08 Python
新加坡时尚网上购物:Zalora新加坡
2016/07/26 全球购物
技术股东合作协议书
2014/12/02 职场文书
博士给导师的自荐信
2015/03/06 职场文书
2015年个人招商工作总结
2015/04/25 职场文书
致三级跳运动员加油稿
2015/07/21 职场文书
2019朋友新婚祝福语精选
2019/10/10 职场文书
pytorch中F.avg_pool1d()和F.avg_pool2d()的使用操作
2021/05/22 Python
三种方式清除vue路由跳转router-link的历史记录
2022/04/10 Vue.js