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 21 Golang
基于Golang 高并发问题的解决方案
May 08 Golang
Golang中异常处理机制详解
Jun 08 Golang
Go 语言结构实例分析
Jul 04 Golang
golang内置函数len的小技巧
Jul 25 Golang
Go语言基础函数基本用法及示例详解
Nov 17 Golang
深入理解go缓存库freecache的使用
Feb 15 Golang
GO语言字符串处理函数之处理Strings包
Apr 14 Golang
Golang ort 中的sortInts 方法
Apr 24 Golang
详解Go语言中Get/Post请求测试
Jun 01 Golang
go goth封装第三方认证库示例详解
Aug 14 Golang
Go gorilla/sessions库安装使用
Aug 14 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利用str_replace防注入的方法
2013/11/10 PHP
php强制运行广告的方法
2014/12/01 PHP
Laravel中encrypt和decrypt的实现方法
2017/09/24 PHP
thinkPHP5实现的查询数据库并返回json数据实例
2017/10/23 PHP
Javascript 面向对象 重载
2010/05/13 Javascript
将字符串转换成gb2312或者utf-8编码的参数(js版)
2013/04/10 Javascript
js带按钮的提示框可供选择示例代码
2013/09/17 Javascript
文本框水印提示效果的简单实现代码
2014/02/22 Javascript
Javascript添加监听与删除监听用法详解
2014/12/19 Javascript
JavaScript控制网页平滑滚动到指定元素位置的方法
2015/04/17 Javascript
浅谈javascript的Touch事件
2015/09/27 Javascript
javascript学习指南之回调问题
2016/04/23 Javascript
vue 2.0路由之路由嵌套示例详解
2017/05/08 Javascript
js判断用户是输入的地址请求的路径(实例讲解)
2017/07/18 Javascript
jsTree事件和交互以及插件plugins详解
2017/08/29 Javascript
vue脚手架中配置Sass的方法
2018/01/04 Javascript
Vue路由守卫之路由独享守卫
2019/09/25 Javascript
微信公众号H5之微信分享常见错误和问题(小结)
2019/11/14 Javascript
5个你不知道的JavaScript字符串处理库(小结)
2020/06/01 Javascript
微信小程序实现身份证取景框拍摄
2020/09/09 Javascript
python 环境变量和import模块导入方法(详解)
2017/07/11 Python
Python实现的逻辑回归算法示例【附测试csv文件下载】
2018/12/28 Python
PyQt5的安装配置过程,将ui文件转为py文件后显示窗口的实例
2019/06/19 Python
python二维码操作:对QRCode和MyQR入门详解
2019/06/24 Python
Django+RestFramework API接口及接口文档并返回json数据操作
2020/07/12 Python
2014年毕业演讲稿范文
2014/05/13 职场文书
关于旅游的活动方案
2014/08/15 职场文书
党委班子对照检查材料
2014/08/19 职场文书
出租房屋协议书
2014/09/14 职场文书
学生逃课检讨书1000字
2014/10/20 职场文书
保管员岗位职责
2015/02/14 职场文书
小学教师教育随笔
2015/08/14 职场文书
高考百日冲刺决心书
2015/09/23 职场文书
python爬虫--selenium模块
2021/03/31 Python
MySQL 分组查询的优化方法
2021/05/12 MySQL
python获取带有返回值的多线程
2022/05/02 Python