15、Context

news2024/11/24 1:47:15

目录

  • 一、常规gorutine控制
  • 二、context控制groutine
    • 1 - 使用context控制单个gorutine
    • 2 - context创建
    • 3 - context函数
    • 4 - Context接口
    • 5 - 使用context控制多个gorutine停止

一、常规gorutine控制

  • 控制并发的两种方式
    • 使用WaitGroup:多个Goroutine执行同一件事情
    • 使用Context
  • WaitGroup简单示例:控制多个Go程,全部执行结束后,主线程才允许退出
package main

import (
	"fmt"
	"sync"
	"time"
)

func main() {
	var wg sync.WaitGroup
	wg.Add(2)

	go func() {
		time.Sleep(2 * time.Second)
		fmt.Println(time.Now().Unix(), " -> job one down")
		wg.Done()
	}()

	go func() {
		time.Sleep(1 * time.Second)
		fmt.Println(time.Now().Unix(), " -> job two down")
		wg.Done()
	}()

	fmt.Println(time.Now().Unix(), " -> before block")
	wg.Wait() //阻塞等待所有的job执行结束
	fmt.Println(time.Now().Unix(), " -> after block")
}

在这里插入图片描述

  • Channel+select控制gorutine
package main

import (
	"fmt"
	"time"
)

func main() {
	stop := make(chan bool)

	go func() {
		for {
			select {
			case <-stop:
				fmt.Println(time.Now().Unix(), " -> got the stop channel")
				return

			default:
				fmt.Println(time.Now().Unix(), " -> still working")
				time.Sleep(1 * time.Second)
			}
		}
	}()

	time.Sleep(5 * time.Second)
	fmt.Println(time.Now().Unix(), " -> stop the gorutine")
	stop <- true
	time.Sleep(5 * time.Second)
}

在这里插入图片描述

二、context控制groutine

  • 多个Gorutine或者多个Gorutine内部又有Goroutine的情况如何控制:使用context
    在这里插入图片描述

1 - 使用context控制单个gorutine

  • 使用context控制单个gorutine
package main

import (
	"context"
	"fmt"
	"time"
)

func main() {
	ctx, cancel := context.WithCancel(context.Background())
	go func() {
		for {
			select {
			case <-ctx.Done():
				fmt.Println(time.Now().Unix(), " -> got the stop channel")
				return
			default:
				fmt.Println(time.Now().Unix(), " -> still working")
				time.Sleep(1 * time.Second)
			}
		}
	}()

	time.Sleep(5 * time.Second)
	fmt.Println(time.Now().Unix(), " -> stop the gorutine")
	cancel()
	time.Sleep(5 * time.Second)
}

2 - context创建

  • context.Background():函数返回一个空context,通过 new(emptyCtx) 语句初始化,指向私有结构体 context.emptyCtx 的指针
  • context.TODO():函数返回一个空context,通过 new(emptyCtx) 语句初始化,指向私有结构体 context.emptyCtx 的指针
  • go源码
var (
	background = new(emptyCtx)
	todo       = new(emptyCtx)
)

// Background returns a non-nil, empty Context. It is never canceled, has no
// values, and has no deadline. It is typically used by the main function,
// initialization, and tests, and as the top-level Context for incoming
// requests.
func Background() Context {
	return background
}

// TODO returns a non-nil, empty Context. Code should use context.TODO when
// it's unclear which Context to use or it is not yet available (because the
// surrounding function has not yet been extended to accept a Context
// parameter).
func TODO() Context {
	return todo
}
  • Background和TODO区别:context.Background 和 context.TODO 函数其实也只是互为别名,没有太大的差别,它们只是在使用和语义上稍有不同
    • context.Background 是上下文的默认值,所有其他的上下文都应该从它衍生(Derived)出来
    • context.TODO 应该只在不确定应该使用哪种上下文时使用

在多数情况下,如果当前函数没有上下文作为入参,我们都会使用 context.Background 作为起始的上下文向下传递

3 - context函数

  • context函数
    • 以下4个方法的参数partent,就是父Context,要基于这个父Context创建出子Context;这种方式可以理解为子Context对父Context的继承,也可以理解为基于父Context的衍生
    • 给一个函数方法传递Context的时候,不要传递nil,如果不知道传递什么,就使用context.TODO
    • Context是线程安全的,可以放心的在多个goroutine中传递。同一个Context可以传给使用其的多个goroutine,且Context可被多个goroutine同时安全访问
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
func WithDeadline(parent Context, d time.Time) (Context, CancelFunc)
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
	return WithDeadline(parent, time.Now().Add(timeout))
}
func WithValue(parent Context, key, val any) Context
  • WithCancel:传递一个父Context作为参数,返回子Context,以及一个取消函数用来取消Context(永远不要传递取消函数)
  • WithDeadline:WithDeadline和WithCancel,多传递一个截止时间参数,意味着到了这个时间点,会自动取消Context,当然我们也可以不等到这个时候,可以提前通过取消函数进行取消
  • WithTimeout:查看源码实现可以看到和WithDeadline其实是一样的,WithDeadline是绝对时间,WithTimeout是以当前时间为起始的持续时间
  • WithValue:WithValue函数和取消Context无关,它是为了生成一个绑定了一个键值对数据的Context,这个绑定的数据可以通过Context.Value方法访问到
    • 值 val 与 key 关联,并通过 context 树与 context 一起传递
    • 一旦获得带有值的 context,从中派生的任何 context 都会获得此值
    • WithValue返回valueCtx的指针,valueCtx包含三个成员context、key、val
    • 不建议使用 context 值传递关键参数
    • key不建议使用string或其他内置类型,所以建议自定义key类型

4 - Context接口

  • Deadline:返回 context.Context 被取消的时间,也就是完成工作的截止日期
  • Done:返回一个 Channel,这个 Channel 会在当前工作完成或者上下文被取消之后关闭,多次调用 Done 方法会返回同一个 Channel
  • Err:返回 context.Context 结束的原因,它只会在 Done 返回的 Channel 被关闭时才会返回非空的值
    • 如果 context.Context 被取消,会返回 Canceled 错误
    • 如果 context.Context 超时,会返回 DeadlineExceeded 错误
  • Value:从 context.Context 中获取键对应的值,对于同一个上下文来说,多次调用 Value 并传入相同的 Key 会返回相同的结果,该方法可以用来传递请求特定的数据
type Context interface {
	Deadline() (deadline time.Time, ok bool)

	Done() <-chan struct{}

	Err() error

	Value(key any) any
}

5 - 使用context控制多个gorutine停止

package main

import (
	"context"
	"fmt"
	"time"
)

func main() {
	ctx, cancel := context.WithCancel(context.Background())

	go worker(ctx, "node01")
	go worker(ctx, "node02")
	go worker(ctx, "node03")
	time.Sleep(5 * time.Second)
	fmt.Println(time.Now().Unix(), " -> stop the gorutine")
	cancel()
	time.Sleep(5 * time.Second)
}

func worker(ctx context.Context, name string) {
	go func() {
		for {
			select {
			case <-ctx.Done():
				fmt.Println(time.Now().Unix(), " -> ", name, " got the stop channel")
				return
			default:
				fmt.Println(time.Now().Unix(), " -> ", name, " still working")
				time.Sleep(1 * time.Second)
			}
		}
	}()
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/457167.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SQL经典50题总结

SQL经典50题总结 SQL经典50题总结1.数据准备50题1.查询"01" 课程比 "02" 课程成绩高的学生的信息及课程分数2.查询平均成绩大于等于 60 分的同学的学生编号和学生姓名和平均成绩3.查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩4.查询姓“…

推荐一个开源的区块链开发者工具网站

开源区块链开发者工具箱 https://ChainTool.tech 今天可以正式上线了。ChainTool 使用完全开源的方式编写一些开发者日常经常使用的工具。 关于 ChainToolDAO 大约在两个月前&#xff0c; ChainToolDAO 成立了&#xff0c;成立 ChainToolDAO 的来由是这样的&#xff1a;我是一…

Python模块练习题-测试你的Python技能。

练习题&#xff1a; 1.logging模块有几个日志级别&#xff1f;2.请配置logging模块&#xff0c;使其在屏幕和文件里同时打印以下格式的日志3.json、pickle、shelve三个区别是什么&#xff1f;4.json的作用是什么&#xff1f;5.subprocess执行命令方法有几种&#xff1f;6.为什么…

idea 2023版本创建maven管理的Scala项目教程

目录 1、创建项目1.1、创建项目名及简单配置1、2 刚开始创建好后的项目是这样的1、3 进行相关设置1&#xff09;增加maven管理2&#xff09;增加scala目录&#xff0c;并设置成resource目录 注意&#xff1a; 本项目写得教程是基于您得Java jdk、Scala jdk、maven这些都是安装配…

汽车充电桩检测设备TK4860C交流充电桩检定装置

TK4860C是一款在交流充电桩充电过程中实时检测充电电量的标准仪器&#xff0c;仪器以新能源车为负载&#xff0c;结合宽动态范围测量技术、电能ms级高速刷新等技术&#xff0c;TK4860C实现充电全过程的累积电能精准计量&#xff0c;相比于传统的预设检定点的稳态计量&#xff0…

PyQt5、Pyside2学习---02

1.界面布局 我们最常用的 Layout布局 有4种&#xff0c;分别是 QHBoxLayout 水平布局QVBoxLayout 垂直布局QGridLayout 表格布局QFormLayout 表单布局 2.调整控件位置和大小 调整layout中控件的大小比例: 可以通过设定控件的sizePolicy来调整&#xff0c; 调整控件间距: …

kafka多用户访问权限配置指导

一、场景描述 现场业务由于多厂商集成,共享数据需要,需对接当前kafka集群,为做到类似租户隔离的功能,需要开启kafka的权限控制和动态用户管理功能,实现不同厂商访问被授权的合法资源,消费者账号只能消费数据,生产者账号只能生产数据。 二、控制方式 Kafka 有三种认证模…

VSCode查看和编辑远程服务器的代码

在嵌入式开发过程中&#xff0c;很多时候代码都是放在编译服务器上&#xff0c;并给每个项目成员分配一个账号。这时候访问代码&#xff0c;可以通过 Samba 服务器将代码目录挂载到本地&#xff0c;再通过 VSCode 去打开服务器的代码。 但是&#xff0c;这时候我经常碰到通过 …

vue项目 解决el-table自适应高度,vue页面不显示多条滚动条,超出的部分让el-table内部出现滚动条

一、需求 后台管理系统&#xff1a;最常见的页面都是由—>左侧菜单、头部tabView页签、主体数据渲染页面&#xff08;AppMain&#xff09;&#xff1b;而一般AppMain页面又分为&#xff1a; 搜索区域、table数据&#xff08;分页&#xff09;&#xff0c;可能也会存在底部&a…

编译原理实验1——词法分析器的Java实现

一、 实验目的 设计并实现一个PL/0语言(或其它语言的子集,如C语言的子集)的词法分析程序&#xff0c;加深对词法分析原理的理解。 二、实验原理 词法分析是从左向右扫描每行源程序的符号&#xff0c;拼成单词&#xff0c;换成统一的机内表示形式——TOKEN字&#xff0c;送给…

由浅入深MFC学习摘记--第四部分上

目录 第八章 Document-View结构为什么使用Document-View结构DocumentviewDocumentFrameDocumentTemplateCDocTemplate、CDocument、CView、CFrameWnd 之间的关系 Document - 数据结构设计容器选用范例修改线条与点 View-重绘与编辑代码修改View 的重绘鼠标消息处理类向导 Seria…

手推FlinkML2.2(三)

SQLTransformer&#xff08;SQL转换器&#xff09;是一种数据预处理方法&#xff0c;允许您使用SQL语句对数据进行转换和操作。SQL转换器通常用于数据清洗、特征工程和数据聚合等任务&#xff0c;以提高数据分析和机器学习模型的性能。它可以与各种数据处理和存储系统&#xff…

后端大厂面试总结大全六

目录&#xff1a; 1、Transactional注解控制事务有哪些不生效的场景2、MySQL的优化 1、Transactional注解控制事务有哪些不生效的场景 数据库引擎不支持事务数据源没有配置事务管理器没有被spring管理方法不是public的同一个类中方法调用&#xff0c;导致Transactional失效 举…

2023云数据库技术沙龙MySQL x ClickHouse专场成功举办

4月22日&#xff0c;2023首届云数据库技术沙龙 MySQL x ClickHouse 专场&#xff0c;在杭州市海智中心成功举办。本次沙龙由玖章算术、菜根发展、良仓太炎共创联合主办。围绕“技术进化&#xff0c;让数据更智能”为主题&#xff0c;汇聚字节跳动、阿里云、玖章算术、华为云、腾…

gitee教程

二、安装git 要使用gitee&#xff0c;需要先安装git工具。git工具下载&#xff1a;Git - Downloadshttps://git-scm.com/downloads 下载好后,检查是否真的下载了&#xff1a; 三、登录gitee 我们先在 gitee上注册账号并登录。gitee官网&#xff1a;Gitee - 企业级 DevOps 研…

LINUX SVN 新建项目

从第三方代码创建代码库&#xff1a; 1、通过客户端进入服务端 2、在对应的目录创建新的项目/目录 在对应的目录右击 &#xff1a;creat folder... 例&#xff1a;创建testSvn 3、在客户端checkout(co) testSvn 4、将第三方源码(srcTest)拷贝到客户端下的对应路径 防止L…

Redis缓存更新策略

缓存更新是redis为了节约内存而设计出来的一个东西&#xff0c;主要是因为内存数据宝贵&#xff0c;当我们向redis插入太多数据&#xff0c;此时就可能会导致缓存中的数据过多&#xff0c;所以redis会对部分数据进行更新&#xff0c;或者把他叫为淘汰更合适。 1.缓存更新三种策…

Windows 自带环境变量

目录 Windows自带环境变量说明Windows自带环境变量总结 所谓 Windows 环境变量&#xff0c;指的是 Windows 指定操作系统工作环境的一些设置选项或属性参数&#xff0c;比方说指定系统文件夹或临时文件夹的位置等。与常量相比&#xff0c;一个环境变量往往由变量名称和变量值组…

深入了解Android系统中的音视频编解码器:MediaCodec

Media内核源码 Media内核是Android系统中负责音视频处理的核心模块&#xff0c;包括音视频采集、编解码、传输、播放等功能。Media内核源码位于Android源码树的/frameworks/av目录下&#xff0c;主要包括以下模块&#xff1a; media/libstagefright&#xff1a;包含了Media F…

设计模式——组件协作模式之策略模式

文章目录 前言一、“组件协作” 模式二、Strategy 策略模式1、动机2、模式定义3、代码示例4、结构 要点总结 前言 一、“组件协作” 模式 现代软件专业分工之后的第一个结果是 “框架与应用程序的划分”&#xff0c;“组件协作” 模式通过晚期绑定&#xff0c;来实现框架与应用…