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缓冲channel和非缓冲channel的区别说明
Apr 25 Golang
Go语言中的UTF-8实现
Apr 26 Golang
Golang二维数组的使用方式
May 28 Golang
基于Go语言构建RESTful API服务
Jul 25 Golang
Go语言应该什么情况使用指针
Jul 25 Golang
使用GO语言实现Mysql数据库CURD的简单示例
Aug 07 Golang
Go 通过结构struct实现接口interface的问题
Oct 05 Golang
如何利用golang运用mysql数据库
Mar 13 Golang
Golang解析JSON对象
Apr 30 Golang
Go语言入门exec的基本使用
May 20 Golang
Go语言编译原理之变量捕获
Aug 05 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 和 MySQL 时区的一点总结
2008/03/26 PHP
PHP小偷程序的设计与实现方法详解
2016/10/15 PHP
php生成网页桌面快捷方式
2017/05/05 PHP
PHP生成短网址的思路以及实现方法的详解
2019/03/25 PHP
浅析js封装和作用域
2013/07/09 Javascript
JS实现点击按钮后框架内载入不同网页的方法
2015/05/05 Javascript
canvas 弹幕效果(实例分享)
2017/01/11 Javascript
基于vue实现分页/翻页组件paginator示例
2017/03/09 Javascript
详解AngularJS1.6版本中ui-router路由中/#!/的解决方法
2017/05/22 Javascript
js实现数组和对象的深浅拷贝
2017/09/30 Javascript
vue mint-ui 实现省市区街道4级联动示例(仿淘宝京东收货地址4级联动)
2017/10/16 Javascript
Vue实现购物车实例代码两则
2020/05/30 Javascript
react结合bootstrap实现评论功能
2020/05/30 Javascript
[01:14:31]Secret vs VG 2018国际邀请赛淘汰赛BO3 第一场 8.23
2018/08/24 DOTA
Python中非常实用的一些功能和函数分享
2015/02/14 Python
浅谈Python爬取网页的编码处理
2016/11/04 Python
Python做简单的字符串匹配详解
2017/03/21 Python
浅谈Python黑帽子取代netcat
2018/02/10 Python
python 寻找list中最大元素对应的索引方法
2018/06/28 Python
使用Flask-Cache缓存实现给Flask提速的方法详解
2019/06/11 Python
sklearn线性逻辑回归和非线性逻辑回归的实现
2020/06/09 Python
什么是Smarty变量操作符?如何使用Smarty变量操作符
2014/07/18 面试题
Java中采用什么结构来捕获、处理异常?各子句的顺序、功能如何
2013/10/07 面试题
汽车技术服务与营销专业在籍生自荐信
2013/09/28 职场文书
生产部经理岗位职责
2013/12/16 职场文书
天鹅的故事教学反思
2014/02/04 职场文书
企业负责人任命书
2014/06/05 职场文书
大专学生求职自荐信
2014/07/06 职场文书
物流管理专业推荐信
2014/09/06 职场文书
软环境建设心得体会
2014/09/09 职场文书
文案策划岗位职责
2015/02/11 职场文书
小学班主任工作经验交流材料
2015/11/02 职场文书
Python中的xlrd模块使用整理
2021/06/15 Python
Java elasticsearch安装以及部署教程
2021/06/28 Java/Android
python文件与路径操作神器 pathlib
2022/04/01 Python
【海涛教你打DOTA】黑鸟第一视角解说
2022/04/01 DOTA