go语言中channel类型
目录
一、什么是channel
二、为什么要有channel
三、channel操作使用
初始化
操作
单向channel
双向channel,可读可写
四、close下什么场景会出现panic
五、总结
一、什么是channel
Channels are a typed conduit through which you can send and receive values with the channel operator, <-.
channel是go语言的核心类型之一,翻译为中文是“通道,管道”,为了实现协程间的同步与通信。遵循FIFO(先进先出)的队列,保证线程安全。
二、为什么要有channel
“不要用共享内存来通信,而是使用通信来共享内存” -- go语言并发哲学
任何一种程序语言要实现并发能力,就要做好多线程之间的协调工作,让彼此知道对方状态,获取对方的信息,完成预定任务。大多数的编程语言的并发编程模型是基于线程和内存同步访问控制,go语言的并发编程的模型则用 goroutine 和 channel 来实现。channel是goroutine之间架了一条管道,在管道里传输数据,实现goroutine间的通信来协调工作(当然goroutine实现通信不止channel一种,还有 go语言中协程实现通信的三种方式 context\sync.cond\channel)。
在go语言中,CSP(Communicating Sequential Processes)模型是go语言并发编程哲学的实现(三种线程模型与CSP实现),goroutine与channel是CSP上层实现的两大基石。
channel的底层实现保证了协程操作安全:在任何同一时间内,channel中的一个数据只允许一个协程访问,不存在数据竞争。
三、channel操作使用
初始化
channel是引用类型,有带缓冲channel和无缓冲channel,未初始化的channel值是nil。通过内建函数make (仅对map\slice\channel初始化)分配内存并初始化。
操作
channel只有三种操作方式Send、Receive、close。
通过操作符 <- 实现发送或读取数据(中文社区更愿意把Send和接收,从通信操作符号看chan <- 是发送数据到chan,<- chan是接收chan中数据,这是从通信角度理解。从读写角度理解,我更愿意翻译为chan <- 为写入数据到chan,<-chan为从chan读取数据出来)。数据为go中任意类型:
close为关闭chan:close(chan)
虽然go语言采自动垃圾回收机制来管理内存,但go的垃圾回收器不会主动回收运行中的channel, 主动关闭channel为了防止内存泄露。
单向channel
单向channel分为write-only,read-only channel,主要作用有限制通信方向、减少竞态条件、提高代码可读性。
限制通信方向:使用只写通道可以在某些情况下限制通信的方向,确保特定的协程只能发送数据到通道,而不会在不适当的地方进行接收操作。这有助于清晰地定义协程之间的职责和交互。
减少竞态条件:当只有一个协程负责向通道发送数据,而其他协程只负责接收时,可以减少竞态条件的出现。这有助于避免数据竞争和复杂的同步问题。
提高代码可读性:通过使用只写通道,你可以在代码中清楚地表达协程的作用。这有助于其他开发人员更容易地理解代码并阅读文档。
unc worker(id int, jobs <-chan int, results chan<- int) {for job := range jobs {fmt.Printf("Worker %d started job %d\n", id, job)time.Sleep(time.Millisecond)fmt.Printf("Worker %d finished job %d\n", id, job)results <- job * 2}
}func main() {numJobs := 5jobs := make(chan int, numJobs)results := make(chan int, numJobs)// 启动3个工作协程for i := 1; i <= 3; i++ {go worker(i, jobs, results)}// 向通道发送任务for j := 1; j <= numJobs; j++ {jobs <- j}close(jobs)// 收集结果for r := 1; r <= numJobs; r++ {result := <-resultsfmt.Println("Result:", result)}
}
在这个示例中,我们使用只写通道 chan<- 来传递任务给工作协程,工作协程的<- chan只负责从通道中接收任务。这种模式将任务分发和执行解耦,增加了代码的可读性和可维护性。
总之,单向channel在go语言中用于限制通道的使用方向,有助于提高代码的可读性、降低竞态条件和减少复杂性。
双向channel,可读可写
基本通道使用:创建一个通道,发送数据到通道,然后从通道接收数据
func base() {ch := make(chan int) // 创建一个通道go func() {ch <- 42 // 发送数据到通道}()value := <-ch // 从通道接收数据fmt.Println("Received:", value) // Received: 42
}
使用缓冲通道:创建带有缓冲区的通道,可以存储多个数据,然后使用循环向通道发送和接收数据。
func cacheChan() {ch := make(chan int, 2) // 创建一个容量为2的缓冲通道ch <- 1ch <- 2value1 := <-chvalue2 := <-chfmt.Println("Received:", value1, value2) // Received: 1 2
}
协程池: 使用通道来实现一个简单的协程池,从通道中获取任务并分发给协程进行处理。
func worker(id int, jobs <-chan int, results chan<- int) {for job := range jobs {fmt.Printf("Worker %d started job %d\n", id, job)time.Sleep(time.Millisecond)fmt.Printf("Worker %d finished job %d\n", id, job)results <- job * 2}
}func goroutinePool() {numJobs := 5numWorkers := 3jobs := make(chan int, numJobs)results := make(chan int, numJobs)for i := 1; i <= numWorkers; i++ {go worker(i, jobs, results)}for j := 1; j <= numJobs; j++ {jobs <- j}close(jobs)var wg sync.WaitGroupwg.Add(numJobs)go func() {wg.Wait()close(results)}()for r := range results {fmt.Println("Result:", r)wg.Done()}
}
取消协程: 使用通道来实现协程的取消,通过发送信号告知协程停止工作。
func worker(cancel <-chan struct{}) {for {select {case <-cancel:fmt.Println("Worker canceled")returndefault:fmt.Println("Working...")time.Sleep(time.Second)}}
}func cancelRoutine() {cancel := make(chan struct{})go worker(cancel)time.Sleep(3 * time.Second)fmt.Println("Canceling worker...")close(cancel)time.Sleep(1 * time.Second)
}
四、close下什么场景会出现panic
在使用channel时,为了获得良好的协程同步与通信结果,在一些场景下会导致程序panic,
如下为读写与channel状态对协程的影响表:
调用close关闭channel时,未初始化时关闭、重复关闭、关闭后发送、发送时关闭,在这四种情况下会出现panic:
未初始化就关闭
func main() {var ch chan intclose(ch) // panic: close of nil channel
}
重复关闭
func main() {ch := make(chan int)close(ch)close(ch) // panic: close of closed channel
}
关闭后发送
func main() {wg := sync.WaitGroup{}wg.Add(1)ch := make(chan int)close(ch)go func() {defer wg.Done()ch <- 1 // panic: send on closed channel}()<-chwg.Wait()
}
发送后关闭
func main() {ch := make(chan int)var wg sync.WaitGroupwg.Add(1)go func() {defer wg.Done()defer fmt.Println("close ch") // close chdefer close(ch)go func() {ch <- 1 // panic: send on closed channel}()}()fmt.Println(<-ch)wg.Wait()
}
不正确地关闭channel会导致程序panic,如何优雅关闭channel呢?
参看:《How to Gracefully Close Channels》
五、总结
本内容主要讲述了channel的基础知识,包括定义、使用背景、类型、操作方式、使用场景、不正确关闭channel会panic的场景。没有对channel的底层实现原理进行解读,参看channel的底层实现原理了解。
相关文章:
go语言中channel类型
目录 一、什么是channel 二、为什么要有channel 三、channel操作使用 初始化 操作 单向channel 双向channel,可读可写 四、close下什么场景会出现panic 五、总结 一、什么是channel Channels are a typed conduit through which you can send and receive …...
基于STM32F1的电子罗盘HMC5883L角度测量
基于STM32F1的电子罗盘HMC5883L角度测量 参考 1. HMC5883L模块 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Axqqv48y-1692885921487)(…\img\HMC5883L.png)] 型号:GY-271使用芯片:HMCL5883L供电电源:3-5V通…...
Oracle解锁表、包、用户、杀会话、停job
Oracle解锁表、包、用户、杀会话、停job 一、创建包tzq_server_pkg二、授权给需要使用的用户log三、解锁表:执行存过unlock_table(schema_name, table_name)四、解锁包:执行存过unlock_package(schema_name, pkg_name)五、解锁用户:执行存过u…...
软考高级系统架构设计师系列论文九十九:论软件开发平台的选择和应用
软考高级系统架构设计师系列论文九十九:论软件开发平台的选择和应用 一、相关知识点二、摘要三、正文四、总结一、相关知识点 软考高级系统架构设计师系列之:面向构件的软件设计,构件平台与典型架构二、摘要 本文从一个行业MIS系统的开发实践,讨论了软件开发平台的选择和应…...
Redis Pub/Sub 指南
Redis 不仅仅是一个数据库,还可以作为支持发布和订阅(Pub/Sub)操作的消息代理。本文将使用 Navicat for Redis 简要概述 Redis 的 Pub/Sub 功能。 关于发布或订阅消息范式 Pub/Sub 是一种模式,发送者(广播者…...
Nest(2):Nest 应用目录结构和脚手架命令介绍
Nest 应用目录结构和脚手架命令介绍 在正式使用 NestJS 进行开发之前,先来了解下 Nest 应用的目录结构,和一些常用的脚本命令。 工程目录 下面是使用 nest/cli 创建的 Nest 项目的目录结构。 上篇文章中介绍了 src 目录以及目录下各个文件的作用。下面…...
【嵌入式】MKV31F512VLL12 微控制器 (MCU) 、Cyclone® IV E EP4CE10E22I8LN,FPGA-现场可编程门阵列芯片
1、MKV31F512VLL12 微控制器 (MCU) 是适用于BLDC、PMSM和ACIM电机控制应用的高性能解决方案。这些MCU采用运行频率为100MHz/120MHz、带数字信号处理 (DSP) 和浮点单元 (FPU) 的ARM Cortex-M4内核。KV3x MCU配备两个采样率高达1.2MS/s的16位ADC、多个控制定时器以及512KB闪存。 …...
矢量调制分析基础
前言 本文介绍VSA 的矢量调制分析和数字调制分析测量能力。某些扫频调谐频谱分析仪也能通过使用另外的数字无线专用软件来提供数字调制分析。然而,VSA 通常在调制格式和解调算法配置等方面提供更大的测量灵活性,并提供更多的数据结果和轨迹轨迹显示。本…...
ensp-Ipv6配置配置
ensp-Ipv6配置配置 📎ipv6.zip📎Ipv6 网络.docx...
java八股文面试[java基础]—— hashCode 与 equals 区别 == 与 equals的区别
两个对象的hashCode()相同时,equals()相等吗?_两个对象的hashcode一样,equal一样么_不想当个程序员的博客-CSDN博客 equals():比较的是非基本类型的数据的引用地址(即内存地址)是否相同,但是对于重写equal…...
Dubbo之PojoUtils源码分析
功能概述 PojoUtils是一个工具类,能够进行深度遍历,将简单类型与复杂类型的对象进行转换,在泛化调用时用到(在泛化调用中,主要将Pojo对象与Map对象进行相互转换) 功能分析 核心类PojoUtils分析 主要成员…...
【C++】—— C++11新特性之 “右值引用和移动语义”
前言: 本期,我们将要的介绍有关 C右值引用 的相关知识。对于本期知识内容,大家是必须要能够掌握的,在面试中是属于重点考察对象。 目录 (一)左值引用和右值引用 1、什么是左值?什么是左值引用…...
谈一谈redis脑裂
什么是redis脑裂 (1)一主多从架构中,主节点与客户端通信正常,主节点与哨兵、从节点连接异常,客户端仍正常写入数据 (2)哨兵判定主节点下线,重新选主 (3)原主…...
基于原生Servlet使用模板引擎Thymeleaf访问界面
我们常在Spring Boot项目中使用Thymeleaf模板引擎,今天突发奇想,尝试原生Servlet访问! 说做就做 搭建完整的WEB项目 其中的大部分依赖都是后续报错 追加进来的 导入依赖 thymeleaf-3.0.11.RELEASE.jar 第一次访问 访问地址: http://localhost:8080…...
【C语言】15-函数-1
1. 初步认识函数 通过前几章的学习,已经可以编写一些简单的 C 语言程序了,但是如果程序的功能比较多,规模比较大,把所有的程序代码都写在一个主函数(main函数)中,就会使主函数变得庞杂、头绪不清,使阅读和维护程序变得困难。此外,有时程序中要多次实现某一功能就需要…...
08-信息收集-架构、搭建、WAF等
信息收集-架构、搭建、WAF等 信息收集-架构、搭建、WAF等一、前言说明二、CMS识别技术三、源码获取技术四、架构信息获取技术五、站点搭建分析1、搭建习惯-目录型站点2、搭建习惯-端口类站点3、搭建习惯-子域名站点4、搭建习惯-类似域名站点5、搭建习惯-旁注,c段站点…...
Qt --- 显示相关设置 窗口属性等
主界面,窗口 最小化 最大化 关闭按钮、显示状态自定义: setWindowFlags(Qt::CustomizeWindowHint); setWindowFlags(Qt::WindowCloseButtonHint); //只要关闭按钮 setWindowFlags(Qt::WindowFlags type) Qt::FrameWindowHint:没有边框的窗口 Qt::Window…...
使用小程序实现左侧菜单,右侧列表双向联动效果
目录 引言理解双向联动效果的重要性scrollview属性介绍实现左侧菜单数据准备渲染菜单列表监听菜单点击事件实现右侧列表数据结构设计初始数据渲染监听列表滚动事件左侧菜单与右侧列表联动获取当前滚动位置计算对应菜单项联动效果优化用户体验考虑平滑滚动效果菜单高亮状态...
selenium中处理验证码问题
验证码 基本作用:可以实现当前访问页面的数据安全性、还可以减少用户的并发数; 类型:1、纯数字、纯字母;2、汉字组合;3、数学运算题;4、滑动;5、图片(选不同的、选相同、成语顺序&…...
EMR电子病历系统 SaaS电子病历编辑器源码 电子病历模板编辑器
EMR(Electronic Medical Record)指的是电子病历。它是一种基于电子文档的个人医疗记录,可以包括病人的病史、诊断、治疗方案、药物处方、检查报告和护理计划等信息。EMR采用计算机化的方式来存储、管理和共享这些信息,以便医生和医…...
一些自定义hooks
文章目录 1、点击框外隐藏弹窗hook 1、点击框外隐藏弹窗hook **描述:**有一个需要自己封装弹窗的组件,实现点击弹窗框外时隐藏弹窗 代码: import { useEffect } from “react”; // 点击框外hooks import { useEffect } from "react&q…...
基于Citespace、vosviewer、R语言的文献计量学可视化分析技术及全流程文献可视化SCI论文高效写作方法
文献计量学是指用数学和统计学的方法,定量地分析一切知识载体的交叉科学。它是集数学、统计学、文献学为一体,注重量化的综合性知识体系。特别是,信息可视化技术手段和方法的运用,可直观的展示主题的研究发展历程、研究现状、研究…...
lEC 61068-2-14_2023环境试验.第2-14部分:试验.试验N:温度变化, 最新版发布
https://download.csdn.net/download/m0_67373485/88251313 lEC 61068-2-14_2023环境试验.第2-14部分:试验.试验N:温度变化 A change of temperature test is intended to determine the effect on the specimen of a changeof temperature or a succession of changes of tem…...
CFDEM学习笔记
本文用来记录自己学习CFDEM的笔记。 资料总结 虚拟机:链接:https://pan.baidu.com/s/1MPMTJQfl76mW0H5bbT_rAg 提取码:rqli 开机密码:530944988 知乎博客:作者说明了如何关闭颗粒碰撞计算来达到提升计算速度。 Githu…...
SpringBoot入门篇1 - 简介和工程创建
目录 SpringBoot是由Pivotal团队提供的全新框架, 其设计目的是用来简化Spring应用的初始搭建以及开发过程。 1.创建入门工程案例 ①创建新模块,选择Spring初始化,并配置模块相关基础信息 ②开发控制器类 controller/BookController.jav…...
MyBatis-Plus updateById不更新null值
文章目录 前言方式一 调整全局的验证策略方式二 调整字段验证注解方式三 使用 UpdateWrapper 前言 在 MyBatis-Plus 中,使用updateById,null字段并不会更新,其实是和更新的策略有关,当然,也有插入策略,本文…...
用pytorch实现AlexNet
AlexNet经典网络由Alex Krizhevsky、Hinton等人在2012年提出,发表在NIPS,论文名为《ImageNet Classification with Deep Convolutional Neural Networks》,论文见:http://www.cs.toronto.edu/~hinton/absps/imagenet.pdf …...
LeetCode560.和为k的子数组
这道题我用的是暴力法,当然也是不断的提交不断发现问题改出来的,比如我之前是算到和大于目标值就break,其实不行因为后面还可以有负数,我把break删了。后面和为目标之后就答案1然后break然后下一次遍历,测试用例中就出…...
echarts 的dataZoom滑块两端文字被遮挡
问题: 期望: 解决方案: 1:调整宽度(4版本的没有width属性) 2. 参考:echarts图标设置dataZoom拖拽时间轴时自动调整两侧文字的位置_datazoom 位置_乌栖曲的博客-CSDN博客 设置文字的定位 cons…...
MongoDB基本使用
在 MongoDB 中我们可以使用use命令来创建数据库,如果该数据库不存在,则会创建一个新的数据库,如果该数据库已经存在,则将切换到该数据库。使用use命令创建数据库的语法格式如下: --use database_name use my_db1;数据…...
物业公司简介模板/宁波谷歌优化
来源:https://docs.microsoft.com/zh-cn/dotnet/api/system.action-1?viewnetframework-4.7.2 Action<T> Delegate 定义 命名空间:SystemAssemblies:System.Runtime.dll, mscorlib.dll, netstandard.dll封装一个方法,该方法只有一个参数并且不返回…...
国务院 政府网站建设要求/网络服务商怎么咨询
firefox43版本无法安装未验证附加组件,利用以下方法: 1、进入firefox about:config页面中 2、搜索xpinstall.signatures.required,将值改为false。 转载于:https://www.cnblogs.com/lcamry/p/5532164.html...
企业网站备案备注/西安网站制作推广
scanner.next()是接收一个字符串 而scanner.next().charAt(0)是接收到一个字符串,而取到这个字符串的第一个元素。...
wordpress设置背景动画/常见的网络营销方法
一. 什么是HTTP事务 HTTP事务 请求命令 响应结果 是HTTP请求的最小处理单元,简单说就是一次完整的请求过程,包括请求的发送和结果的返回,如果只有发送请求,而没有响应结果,则不能算作HTTP事务。 在这里插入图片描…...
唯品会网站建设的目标/google搜索引擎入口下载
这段时间确实遇到一个很有意思的问题。众所周知,Codereview是配置管理过程当中一个相当重要的过程,对于提高代码质量来说有着相当重要的作用。上个月开始公司的过程改进已经推进到了配置管理中的CodeReview这个阶段。对此我首先是考察了各种语言下的静态…...
佛山门户网站建设/网络推广方法有几种
循环中使用闭包,假设我们需要在每次循环中调用循环序号 for(var i 0; i < 10; i) {setTimeout(function() {console.log(i); }, 1000);}上面的代码不会输出数字 0 到 9,而是会输出数字 10 十次。 当 console.log 被调用的时候, 匿名函数保…...