【golang】通道(channel)的基本原理(一)

通道类型的值本身就是并发安全的,这也是Go语言自带的、唯一一个可以满足并发安全性的类型。

声明一个通道类型变量的时候,我们首先要确定该通道类型的元素类型,决定了我们可以通过这个通道传递什么类型的数据。

在初始化通道的时候,make函数除了必须接收这样的类型字面量作为参数,还可以接收一个int类型的参数。

后者是可选的,用于表示该通道的容量。通道的容量,就是指通道最多可以缓存多少个元素值。由此,虽然这个参数是int类型的,但是它是不能小于0的。

当容量为0时,我们可以称通道为非缓冲通道,也就是不带缓冲的通道。当容量大于0时,我们可以称为缓冲通道,也就是带有缓冲的通道。非缓冲通道和缓冲通道有着不同的数据传递方式。

一个通道相当于一个先进先出(FIFO)的队列。也就是说,通道中的各个元素值都是严格地按照发送的顺序排列的,先被发送通道的元素值一定会先被接收。元素值的发送和接收都需要用到操作符<-。我们也可以叫它接送操作符。一个左尖括号紧接着一个减号形象地代表了元素值的传输方向。

package mainimport "fmt"func main() {ch1 := make(chan int, 3)ch1 <- 2ch1 <- 1ch1 <- 3elem1 := <-ch1fmt.Printf("The first element received from channel ch1: %v\n",elem1)
}

上面代码中,声明并初始化了一个元素类型为int、容量为3的通道ch1,并用了三条语句,向该通道先后发送了三个元素值2、1和3.

这里的语句需要这样写:依次敲入通道变量的名称(比如ch1)、接送操作符<-以及想要发送的元素值(比如2),并且这三者之间最好用空格进行分割。

这显然表达了“这个元素值将被发送该通道”这个语义。由于该通道的容量为 3,所以,我可以在通道不包含任何元素值的时候,连续地向该通道发送三个值,此时这三个值都会被缓存在通道之中。

当我们需要从通道接收元素值的时候,同样要用接送操作符<-,只不过,这时需要把它写=在变量名的左边,用于表达“要从该通道接收一个元素值”的语义。

如果我们需要把如此得来的元素值存起来,那么在接收表达式的左边就需要依次添加赋值符号(=或:=)和用于存值的变量的名字。因此,语句elem1 := <-ch1会将最先进入ch1的元素2接收来并存入变量elem1。

对通道的发送和接收操作都有哪些基本的特性?

1.对于同一个通道,发送操作之间是互斥的,接收操作之间也是互斥的。

2.发送操作和接收操作中对元素值的处理都是不可分割的。

3.发送操作在完全完成之前会被阻塞。接受操作也是如此。

问题详解

1.对于同一个通道,发送操作之间是互斥等待,接收操作之间也是互斥的。

在同一时刻,Go语言的运行时系统(以下简称运行时系统)只会执行对同一个通道的任意个发送操作中的某一个。

直到这个元素值完全被移出该通道之后,其他针对该通道的接收操作才可能被执行。即使这些操作是并发执行的也是如此。

另外,对于通道的同一个元素值来说,发送操作和接收操作之间也是互斥的。例如,虽然会出现,正在被复制进通道但未复制完成的元素值,但是这时它绝不会被想接收它的一方看到和取走。

需要注意的细节是,元素值从外界进入通道时会被复制。更具体地说,进入通道的并不是在接收操作符右边的那个元素值,而是它的副本。

另一方面,元素值从通道进入外界时会被移动。这个移动操作实际上包含了两步,第一步是生成正在通道中的这个元素值的副本,并准备给到接收方,第二步是删除在通道中的这个元素值。

2.发送操作和接收操作中对元素值的处理都是不可分割的。

这里的"不可分割"的意思是,它们处理元素值时都是一气呵成的,绝不会被打断。

例如,发送操作要么还没复制元素值,要么已经复制完毕,绝不会出现只复制了一部分的情况。

又例如,接收操作在准备好元素值的副本之后,一定会删除掉通道中的原值,绝不会出现通道中仍有残留的情况。

这既是为了保证通道中元素值的完整性,也是为了保证通道操作的唯一性。对于通道中的同一个元素值来说,它只可能是某一个发送操作放入的,同时也只可能被某一个接收操作取出。

3.发送操作在完全完成之前会被堵塞。接收操作也是如此

发送操作包括了"复制元素值"和"放置副本到通道内部"这两个步骤

在这两个步骤完全完成之前,发起这个发送操作的那句代码会一直堵塞在那里。也就是说,在它之后的代码不会有执行的机会,直到这句代码的阻塞解除。

更细致地说,在通道完成发送操作之后,运行时系统会通知这句代码所在的goroutine,以使它去争取继续运行代码的机会。

接收操作通常包含了"复制通道内的元素值""放置副本到接收方""删除原值"三个步骤

在所有这些步骤完全完成之前,发起该操作的代码也会一直阻塞,直到该代码所在的goroutine收到了运行时系统的通知并重新获得运行机会为止。

如此阻塞代码其实就是为了实现操作的互斥和元素值的完整。

发送操作和接收操作在什么时候可能被长时间的阻塞?

缓冲通道

针对缓冲通道的情况。如果通道已满,那么对它的所有发送操作都会被阻塞,直到通道中有元素值被接收走。

这时,通道会优先通知最早因此而等待的、那个发送操作所在的goroutine,后者会再次执行发送操作。

由于发送操作在这种情况下被阻塞后,它们所在的goroutine会顺序地进入通道内部的发送等待队列,所以通知的顺序总是公平的。

相对的,如果通道已空,那么对它的所有接收操作都会被阻塞,直到通道中有新的元素值出现。这时,通道会通知最早等待的那个接收操作所在的goroutine,并使它再次执行接收操作。

因此而等待的、所有接收操作所在的goroutine,都会按照先后顺序被放入通道内部的接收等待队列。

非缓冲通道

对应非缓冲通道,情况要简单一点。无论是发送操作还是接收操作,一开始执行就会被阻塞,直到配对的操作也开始执行,才会继续传递。由此可见,非缓冲通道是在用同步的方式传递数据。也就是说,只有收发双方对接上了,数据才会被传递。

并且,数据是直接从发送方复制到接收方的,中间并不会用非缓冲通道做中转。相比之下,缓冲通道则在用异步的方式传递数据。

在大多数情况下,缓冲通道会作为收发双方的中间件。正如前文所述,元素值会先从发送方复制到缓冲通道,之后再由缓冲通道复制给接收方。

但是,当发送操作在执行的时候发现空的通道中,正好有等待的接收操作,那么它会直接把元素值复制给接收方。

注意

对于值为nil的通道,不论它的具体类型是什么,对它的发送操作和接收操作都会永久地处于阻塞状态。它们所属的goroutine中的任何代码,都不再会被执行。

由于通道类型是引用类型,所以它的零值就是nil。换句话说,当我们只声明该类型的变量但没有用make函数对它进行初始化时,该变量的值就会是nil所以一定不要忘记初始化通道!

发送操作和接收操作在什么时候会引发panic?

对于一个已初始化,但未来关闭的通道来说,收发操作一定不会引发panic。但是通道一旦关闭,再对它进行发送操作,就会引发panic

当我们把接收表达式的结果同时赋给两个变量时,第二个变量的类型就是一定bool类型。它的值如果为false就说明通道已经关闭,并且再没有元素值可取了。
注意,如果通道关闭时,里面还有元素值未被取出,那么接收表达式的第一个结果,仍会是通道中的某一个元素值,而第二个结果值一定会是true。

因此,通过接收表达式的第二个结果值,来判断通道是否关闭是可能有延时的。

文章学习自郝林老师的《Go语言36讲》

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

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

相关文章

一键批量修改文件夹名称,中文瞬间变日语,轻松搞定重命名

大家好&#xff01;现在为了更好地适应全球化发展&#xff0c;许多人都有了海外交流、旅行、学习的需求。但是难免遇到一个问题&#xff1a;在电脑中的中文文件夹名称如何快速翻译成日语&#xff1f; 首先&#xff0c;第一步&#xff0c;我们需要打开文件批量改名&#xff0c;…

【Unity】编辑器下查找制定文件下的所有特定资源

需求上很简单&#xff0c;就是在编辑器下&#xff0c;找到某个制定文件下的所有特定资源&#xff08;UnityEngine.Object&#xff09;。Unity 没有提供专门的 API&#xff0c;我一开始想在网上搜索代码&#xff0c;发现没有现成可以直接用的。 功能实现本身并不复杂&#xff0c…

AWS EKS 集群自动扩容 Cluster Autoscaler

文章目录 一&#xff0c;需求工作需求说明 二&#xff0c;部署精简命令执行1&#xff0c;要求2&#xff0c;查看EC2 Auto Scaling groups Tag3&#xff0c;创建Serviceaccount需要的Policy&#xff0c;Role4&#xff0c;部署Cluster Autoscaler5&#xff0c;验证6&#xff0c;常…

zotero在不同系统的安装(win/linux)

1 window系统安装 zotero 官网&#xff1a; https://www.zotero.org/ 官方文档 &#xff1a;https://www.zotero.org/support/ (官方)推荐常用的插件: https://www.zotero.org/support/plugins 入门视频推荐&#xff1a; Zotero 文献管理与知识整理最佳实践 点击 exe文件自…

【环境配置】Windows 10 安装 PyTorch 开发环境,以及验证 YOLOv8

Windows 10 安装 PyTorch 开发环境&#xff0c;以及验证 YOLOv8 最近搞了一台Windows机器&#xff0c;准备在上面安装深度学习的开发环境&#xff0c;并搭建部署YOLOv8做训练和测试使用&#xff1b; 环境&#xff1a; OS&#xff1a; Windows 10 显卡&#xff1a; RTX 3090 安…

Bug日记-webstorm运行yarn 命令报错

在windows中输入yarn -v正确输出&#xff0c;在webstrom终端中运行yarn命令输出错误 问题&#xff1a;可能是由于 WebStorm 配置问题导致的。 解决方案&#xff1a; 检查 WebStorm 的终端配置&#xff1a;在 WebStorm 中&#xff0c;点击菜单栏的 “File”&#xff08;文件&am…

DeepSort:基于检测的目标跟踪的经典

本文来自公众号“AI大道理” DeepSORT在SORT的基础上引入了深度学习的特征表示和更强大的目标关联方式&#xff0c;有效地减少了身份切换的数量&#xff0c;缓解了重识别问题。 ​ 1、DeepSORT简介 DeepSORT的主要思想是将目标检测和目标跟踪两个任务相结合。 首先使用目标检…

排序算法分析——什么时候 用 什么排序

排序算法 & 分析 排序算法历史排序算法分析很快的排序较快的排序中等的排序很慢的排序 分析的结果0.没有要求1.对速度有要求2.边排序边操作3.条件1&条件24.在有序数中操作5.条件1&条件4 了解各种排序&#xff0c;详见排序专栏 排序算法历史 纵观排序算法的历史&a…

硬件产品经理:从入门到精通(新书发布)

目录 简介 新书 框架内容 相关课程 简介 在完成多款硬件产品从设计到推向市场的过程后。 笔者于2020年开始在产品领域平台输出硬件相关的内容。 在这个过程中经常会收到很多读者的留言&#xff0c;希望能推荐一些硬件相关的书籍或资料。 其实&#xff0c;笔者刚开始做硬…

10. 实现业务功能--退出登录

目录 1. 实现 Controller 2. 单体测试 3. 实现前端界面 退出的具体实现逻辑如下&#xff1a; 1. 用户访问退出接口 2. 服务器注销 Session( 在 Controller 中可以直接进行处理 &#xff09; 3. 返回成功或失败 4. 如果返回成功浏览器跳转到相应页面 5. 结束 一般来说&#…

使用VS2015打开.pro文件后,编译报错

编译报错内容&#xff1a; MSB8036 找不到 Windows SDK 版本10.0.18362.0。请安装所需的版本的 Windows SDK 或者在项目属性页中或通过右键单击解决方案并选择“重定解决方案目标”来更改 SD 方法&#xff1a; 1.右键点击 Solution上&#xff0c;在弹出的框中点击“Retarget…

调整数组使奇数全部都位于偶数前面

题目内容&#xff1a; 输入一个整数数组&#xff0c;实现一个函数&#xff0c; 来调整该数组中数字的顺序使得数组中所有的奇数位于数组的前半部分&#xff0c; 所有偶数位于数组的后半部分。 题目思路&#xff1a; 将奇数部分放在前半部分&#xff0c;偶数部分放在后半部分&am…

学习笔记230804---restful风格的接口,delete的传参方式问题

如果后端提供的删除接口是restful风格&#xff0c;那么使用地址栏拼接的方式发送请求&#xff0c;数据放在主体中&#xff0c;后端接受不到&#xff0c;当然也还有一种可能&#xff0c;后端在这个接口的接参设置上是req.query接参。 问题描述 今天遇到的问题是&#xff0c;de…

新榜 | CityWalk本地生活商业价值洞察报告

如果说现在有人问&#xff0c;最新的网络热词是什么? “CityWalk”&#xff0c;这可能是大多数人的答案。 近段时间&#xff0c;“CityWalk”刷屏了各种社交媒体&#xff0c;给网友们带来了一场“城市漫步”之旅。 脱离群体狂欢&#xff0c;这个在社交媒体引发热议的词汇背后又…

首发 | FOSS分布式全闪对象存储系统白皮书

一、 产品概述 1. 当前存储的挑战 随着云计算、物联网、5G、大数据、人工智能等新技术的飞速发展&#xff0c;数据呈现爆发式增长&#xff0c;预计到2025年中国数据量将增长到48.6ZB&#xff0c;超过80%为非结构化数据。 同时&#xff0c;数字经济正在成为我国经济发展的新…

RabbitMQ安装配置,笔记整理 RabbitMQ3.12.2版本安装配置

官网下载 RabbitMQ 官方地址&#xff1a;RabbitMQ: easy to use, flexible messaging and streaming — RabbitMQ 下载时需注意Erlang Versions的版本 这里下载的是3.12.2 2.安装依赖环境 在线安装依赖环境&#xff1a; yum install build-essential openssl openssl-dev…

锐捷无线产品运维(Web登录、 命令行登录)

目录 登录AP产品 Console登录&#xff08;只可以现场登录&#xff09; Web/Telnet/SSH登录&#xff08;可以现场、远程登录&#xff09; 配置AP的管理地址 通过Web界面远程登录 通过Telnet、SSH等命令行的方式登录 登录AC产品 Console登录&#xff08;只可以现场登录&a…

[bug] 记录version `GLIBCXX_3.4.29‘ not found 解决方法

在使用mediapipe 这个库的时候&#xff0c;首次使用出现 GLIBCXX_3.4.29’ not found 错误&#xff0c; 看起来是安装mediapipe 的时候自动升级了 matplotlib 这个库&#xff0c;导致依赖的 libstd.so 版本不满足了&#xff0c;GLIBCXX_3.4.29 is an object from libstdc.so.…

【c语言】字符函数与字符串函数(上)

大家好呀&#xff0c;今天给大家分享一下字符函数和字符串函数&#xff0c;说起字符函数和字符串函数大家会想到哪些呢&#xff1f;&#xff1f;我想到的只有求字符串长度的strlen,拷贝字符串的strcpy,字符串比较相同的strcmp,今天&#xff0c;我要分享给大家的是我们一些其他的…