当前位置:网站首页>Go Context基本使用
Go Context基本使用
2022-08-10 14:31:00 【EthanLeo】
Go Context的基本使用
此文章主要是用来介绍一下golang里面context的使用,因为之前一直不太清楚context的用法,以及context的一些基本特性。
Context的使用场景
Context的功能可以从两个方面去体现:
发送终止信号去提供给方法 传递一些公用的数据给多个方法
为什么需要取消操作(终止信号)
简单来说,我们需要一些终止信号,来告诉我们的程序去停止进行一些不必要的工作。
用一个简单的例子来说明:

从客户端发送请求到程序处理再到数据库中,正常流程如下图所示

但是当客户端发送请求后,如果断开链接,那么正常情况下后序的数据库查询操作应该停止,如果没有任何中止信号那么程序会继续执行,但是正常的情况是需要终止继续操作

所以我们就知道为什么需要终止信号了
Go中Context终止信号发送方式
在go中有两个方面去实现终止信号
监听终止事件 发布终止事件
监听终止事件
Context提供了一个Done()的方法,该方法会返回一个channel,每次监听到上下文发送了取消事件的时候,都发送一个空的struct{}到该管道中,所以为了监听到取消事件,我们需要等待 <-ctx.Done()传递的信号量。
func TestListeningCancel(t *testing.T) {
// 测试方法
// 浏览器打开localhost:8000
// 两秒之后会返回request processed
// 如果发送请求后立刻断开那么 ctx.Done() 能够收到信号 执行中断
http.ListenAndServe(":8000", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
fmt.Fprint(os.Stdout, "processing request\n")
select {
case <-time.After(2 * time.Second):
// 2秒后要是收到信号
// 说明请求被执行
w.Write([]byte("request processed"))
case <-ctx.Done():
// 如果请求被取消 输出请求被取消
fmt.Fprint(os.Stderr, "request cancelled")
}
}))
}
发送终止事件
如果你有一个操作要被取消,那么你需要通过上下文发送一个取消事件
我们可以通过Context包里的内置方法WithCancel(),该方法会返回一个context和一个function
ctx,fn :=context.WithCancel()
// 这个方法是假设一个操作失败
func Operation1(ctx context.Context)error{
time.Sleep(100 *time.Millisecond)
return errors.New("failed")
}
func Operation2(ctx context.Context){
select {
case <-time.After(500*time.Millisecond):
fmt.Println("done")
case <-ctx.Done():
fmt.Println("halted operation2")
}
}
func TestEmittingCancel(t *testing.T){
// 创建一个新的context
ctx := context.Background()
// 通过一个原始创建的ctx 将其包装成为一个新的,带有取消方法的ctx
ctx, cancel := context.WithCancel(ctx)
// 执行上面两个操作 ,让一个操作是在一个go routine中
go func() {
err := Operation1(ctx)
if err!=nil{
cancel()
}
}()
// 执行2操作的时候一样用同样的ctx
Operation2(ctx)
}
该示例就是演示,go有一个协程发送了取消的信号的时候,监听相同context的线程也可以收到信号,并执行操作
超时取消
context包也提供了一个超时取消的方法context.WithTimeout,该方法会在倒计时结束之后自动发送取消信号
func TestCancelWithTimeout(t *testing.T){
// 创建一个空ctx
ctx := context.Background()
// 设置超时时间
cxt, _ := context.WithTimeout(ctx, 1*time.Millisecond)
// 创建一个请求 访问谷歌
req, _ := http.NewRequest(http.MethodGet, "http://baidu.com", nil)
// 将带有取消方法的ctx和请求关联
req = req.WithContext(cxt)
client := &http.Client{}
res, err := client.Do(req)
if err!=nil{
fmt.Println("Request failed:", err)
return
}
fmt.Println("Response received, status code:", res.StatusCode)
}
Context Values
当有多个操作需要用到同一个value的时候,context也提供了对应的方法,可以让多个执行方法获取到值,使用这样的方法进行值传递可以保证对改值的操作是线程安全的
const keyID = "id"
func TestContextWithValue(t *testing.T) {
rand.Seed(time.Now().Unix())
ctx := context.WithValue(context.Background(), keyID, rand.Int())
operation1(ctx)
}
func operation1(ctx context.Context) {
log.Println("operation1 for id:", ctx.Value(keyID), " completed")
operation2(ctx)
}
func operation2(ctx context.Context) {
log.Println("operation2 for id:", ctx.Value(keyID), " completed")
}
以上就是context的一些基本操作,后序还需要进入深度研究
边栏推荐
- Using data intelligence, Amazon cloud technology helps companies build endogenous brand growth
- 【POI 2008, BLO】Cut Point
- 王学岗————直播推流(软便)03x264集成与camera推流
- Lack of comparators, op amps come to the rescue!(Op amp is recorded as a comparator circuit)
- 紫金示例
- 无线网络、HTTP缓存、IPv6
- 2012年下半年 系统架构设计师 下午试卷 II
- 每个月工资表在数据库如何存储?求一个设计思路
- 一汽奥迪:持续34年聚焦品质与体验 立足市场需求推进产品迭代
- 图式图例规范尺寸
猜你喜欢
随机推荐
MQTT服务器搭建
Lithium battery technology
Flask框架——基于Celery的后台任务
DB2查询2个时间段之间的所有月份,DB2查询2个时间段之间的所有日期
MySQL advanced (thirty-three) MySQL data table adding fields
@RequestBody的使用[通俗易懂]
How does IT Xiaobai learn PHP systematically
格式化输出当前时间
laravel throws the error to Dingding
Steam教育在新时代中综合学习论
串口服务器调试助手使用教程,串口调试助手使用教程【操作方式】
$‘\r‘: command not found
PCL 最小二乘拟合空间曲线
【MindSpore易点通机器人-02】设计与技术选型
什么?你还不会JVM调优?
舵机内部结及工作原理浅析[通俗易懂]
How to code like a pro in 2022 and avoid If-Else
学习MySQL 临时表
发送post请求前台无法获取数据
2022-08-10 Daily: Swin Transformer author Cao Yue joins Zhiyuan to carry out research on basic vision models


![[JS Advanced] Creating sub-objects and replacing this_10 in ES5 standard specification](/img/3e/14a1d7c2837c896eaa0ca625eaa040.png)






