Go —— channel (二)

一个空的 channel 会产生哪些问题

读写nil管道均会阻塞触发死锁。关闭的管道仍然可以读取数据,向关闭的管道写数据会触发panic。

问:如果有多个协程同时读取一个channel,channel会如何选择消费者

channel 会按照维护的 recvq 等待读消息的协程队列按照FIFO的顺序选择消费者

我们先来看一下 channel 源码

type hchan struct {qcount   uint           // 当前队列中剩余元素个数dataqsiz uint           // 环形队列长度,即可以存放的元素个数buf      unsafe.Pointer // 环形队列指针 缓冲区elemsize uint16			// 每个元素的大小closed   uint32			// 标识关闭状态elemtype *_type // 元素类型sendx    uint   // 队列下标,指示元素写入时存放到队列中的位置recvx    uint   // 队列下标,指示下一个被读取元素在队列中的位置recvq    waitq  // 等待读消息的协程队列sendq    waitq  // 等待写消息的协程队列lock mutex		// 互斥锁,chan不允许并发读写
}

向管道写数据

向一个管道中写数据的简单过程如下

  • 如果缓冲区中有空余位置,则将数据写入缓冲区,结束发送过程
  • 如果缓冲区中没有空余位置,则将当前协程加入sendq队列,进入休眠并等待被读协程唤醒

简单流程如下图所示

在这里插入图片描述

向管道读数据

channel 会维护一个等待读消息的协程队列 recvq,当一个协程读取消息时的简单过程如下:

  • 如果缓冲区中有数据,则从缓冲区中取出数据,结束读取过程
  • 如果缓冲区中没有数据,则将当前协程加入 recvq 队列,进入休眠并等待被写协程唤醒

如果 sendq 不为空,且没有缓冲区,则会从 sendq队列的第一个协程中获取数据

简单流程如下图所示:

在这里插入图片描述

编写一个程序,测试一下

func main() {c := make(chan int)wg := sync.WaitGroup{}wg.Add(100)go func() {				// G1for {a := <-cfmt.Println("1", a)wg.Done()}}()go func() {				// G2for {a := <-cfmt.Println("2", a)wg.Done()}}()go func() {				// G3for {a := <-cfmt.Println("3", a)wg.Done()}}()go func() {				// G4for {a := <-cfmt.Println("4", a)wg.Done()}}()time.Sleep(1 * time.Second)		// 等待四个协程排好队for i := 0; i < 100; i++ {c <- i}wg.Wait()
}

按照上面协程读取消息的过程会发生什么呢?

  1. 当c还未被写入消息时, G1~G4 以FIFO的原则排好队,比如现在的recvq的顺序为 G1、G2、G3、G4
  2. 当主协程发送消息时,无缓冲区,直接从recvq 队列中取出头部G ,随后再添加到队尾
  3. c中的数据按照G1、G2、G3、G4的顺序依次被读取

那实际执行结果是怎样的呢

在我多次测试后发现前四个数会被每个协程消费一次,随后会出现大片数据被同一协程消费的情况

3 2					// 前四次
3 4
3 5
3 6
3 7
3 8
3 9
3 10
3 11
3 12
3 13
3 14
3 15
3 16
3 17
3 18
3 19
3 20
3 21
3 22
3 23
3 24
3 25
3 26
3 27
3 28
3 29
3 30
3 31
3 32
3 33
3 34
3 35
3 36
3 37
3 38
3 39
3 40
3 41
3 42
3 43
3 44
3 45
3 46
3 47
3 48
3 49
3 50
3 51
3 52
3 53
3 54
3 55
3 56
3 57
3 58
3 59
3 60
3 61
3 62
3 63
3 64
3 65
3 66
3 67
3 68
3 69
3 70
3 71
3 72
3 73
3 74
3 75
3 76
3 77
3 78
3 79
3 80
3 81
3 82
3 83
3 84
3 85
3 86
3 87
3 88
3 89
3 90
3 91
3 92
3 93
3 94
3 95
3 96
3 97
3 98
3 99
2 1					// 前四次
1 0					// 前四次
4 3					// 前四次Process finished with the exit code 0

出现这种情况可能与GMP调度模型有关系,当我们继续增大数据量后(比如增加到10000),会发现每个协程读取chan的次数其实差不多。

当我们向管道写数据时添加一个间隔时间

func main() {c := make(chan int)wg := sync.WaitGroup{}wg.Add(100)go func() {				// G1for {a := <-cfmt.Println("1", a)wg.Done()}}()go func() {				// G2for {a := <-cfmt.Println("2", a)wg.Done()}}()go func() {				// G3for {a := <-cfmt.Println("3", a)wg.Done()}}()go func() {				// G4for {a := <-cfmt.Println("4", a)wg.Done()}}()time.Sleep(1 * time.Second)		// 等待四个协程排好队for i := 0; i < 100; i++ {time.Sleep(1 * time.Millisecond)	// 每隔1ms 发送一次c <- i}wg.Wait()
}

执行程序,会发现按照某种固定的顺序输出,这时完全符合上图的读的过程的

1 0
2 1
3 2
4 3
1 4
2 5
3 6
4 7
...

ps:如果有哪位老哥知道为什么会出现一个协程连续输出的情况,欢迎在评论区讨论

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

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

相关文章

239. 奇偶游戏(带权值并查集,邻域并查集,《算法竞赛进阶指南》)

239. 奇偶游戏 - AcWing题库 小 A 和小 B 在玩一个游戏。 首先&#xff0c;小 A 写了一个由 0 和 1 组成的序列 S&#xff0c;长度为 N。 然后&#xff0c;小 B 向小 A 提出了 M 个问题。 在每个问题中&#xff0c;小 B 指定两个数 l 和 r&#xff0c;小 A 回答 S[l∼r] 中…

苍穹外卖11(Apache ECharts前端统计,营业额统计,用户统计,订单统计,销量排名Top10)

目录 一、Apache ECharts【前端】 1. 介绍 2. 入门案例 二、营业额统计 1. 需求分析和设计 1 产品原型 2 业务规则 3 接口设计 2. 代码开发 3. 功能测试 三、用户统计 1. 需求分析和设计 1 产品原型 2 业务规则 3 接口设计 2. 代码开发 3. 功能测试 四、订单统…

0.开篇:SSM+Spring Boot导学

1. 为什么要使用框架 Spring是一个轻量级Java开发框架&#xff0c;最早有Rod Johnson创建&#xff0c;目的是为了解决企业级应用开发的业务逻辑层和其他各层的耦合问题。 几乎当下所有企业级JavaEE开发都离不开SSM&#xff08;Spring SpringMVC MyBatis&#xff09;Spring B…

什么是企业邮箱?如何选择合适的企业邮箱?

企业邮箱和个人邮箱不同&#xff0c;它的邮箱后缀是企业自己的域名。企业邮箱供应商一般都提供手机app、桌面端、web浏览器访问等邮箱使用途径。那么什么是企业邮箱&#xff1f;如何选择合适的企业邮箱&#xff1f;好用的企业邮箱应具备无缝迁移、协作、多邮箱管理等功能。 企…

【hive】单节点搭建hadoop和hive

一、背景 需要使用hive远程debug&#xff0c;尝试使用无hadoop部署hive方式一直失败&#xff0c;无果&#xff0c;还是使用有hadoop方式。最终查看linux内存占用6GB&#xff0c;还在后台运行docker的mysql(bitnami/mysql:8.0)&#xff0c;基本满意。 版本选择&#xff1a; &a…

全面深入学习Java中的字符串类

二、字符串类 &#xff08;一&#xff09;String String&#xff1a;字符串 concat() --- 在末尾追加字符串&#xff0c;返回新的字符串 substring(int begindex) --- 从指定下标处截取到字符串末尾&#xff0c;并返回新的字符串 substring(int begindex,endindex) --- 从开始…

OceanBase 中一个关于 NOT IN 子查询的 SQL 优化案例

通过一个案例了解 not in 对 NULL 值敏感的处理逻辑和优化方法。 作者&#xff1a;胡呈清&#xff0c;爱可生 DBA 团队成员&#xff0c;擅长故障分析、性能优化&#xff0c;个人博客&#xff1a;[简书 | 轻松的鱼]&#xff0c;欢迎讨论。 爱可生开源社区出品&#xff0c;原创内…

Linux中账号登陆报错access denied

“Access denied” 是一个权限拒绝的错误提示&#xff0c;意味着用户无法获得所请求资源的访问权限。出现 “Access denied” 错误的原因可以有多种可能性&#xff0c;包括以下几种常见原因&#xff1a; 错误的用户名或密码&#xff1a;输入的用户名或密码不正确&#xff0c;导…

机器学习—1.快速入门

机器学习步骤 确定与问题相关的输入&#xff08;明确输入&#xff09;收集与问题相关的数据&#xff08;数据准备&#xff0c;学&#xff09;分析预测结果的类型&#xff08;分类&#xff1f;回归&#xff1f;是判断题还是应用题&#xff09;根据预测记过的类型&#xff0c;选…

http添加SSL证书后打开变成另外一个网站是怎么回事

当在使用http的网站上添加了SSL证书后&#xff0c;如果打开该网站时出现了另外一个网站&#xff0c;可能是由以下几种情况引起的&#xff1a; 错误的证书配置 证书配置可能存在错误&#xff0c;导致SSL连接时服务器返回了错误的证书&#xff0c;或者证书与网站域名不匹配。这…

MySQL-系统及自定义变量

详情系统变量信息参考MySQL官方文档 系统变量分类&#xff1a; 全局系统变量&#xff08;global&#xff09; 全局系统变量针对于所有会话&#xff08;连接&#xff09;有效&#xff0c;但 不能跨重启 会话系统变量&#xff08;session&#xff09; 仅针对当前连接有效&am…

STM32-模数转化器

ADC(Analog-to-Digital Converter) 指模数转换器。是指将连续变化的模拟信号转换 为离散的数字信号的器件。 ADC相关参数说明&#xff1a; 分辨率&#xff1a; 分辨率以二进制&#xff08;或十进制&#xff09;数的位数来表示&#xff0c;一般有 8 位、10 位、12 位、16 位…

Transformer模型-decoder解码器,target mask目标掩码的简明介绍

今天介绍transformer模型的decoder解码器&#xff0c;target mask目标掩码 背景 解码器层是对前面文章中提到的子层的包装器。它接受位置嵌入的目标序列&#xff0c;并将它们通过带掩码的多头注意力机制传递。使用掩码是为了防止解码器查看序列中的下一个标记。它迫使模型仅使用…

WPF 多语言切换及ResourceDictionary的Source路径填写

WPF 多语言切换 1. 添加资源字典 新增两个资源字典&#xff0c;里面分别存储不同语言的文本 <ResourceDictionary xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s…

DRBD双主模式自动化安装部署脚本

DRBD&#xff08;Distributed Replicated Block Device&#xff09;是一种分布式存储系统&#xff0c;它允许在网络中的两个或多个节点之间复制数据。在本例中&#xff0c;我们为两个节点&#xff08;node1和node2&#xff09;设置DRBD&#xff0c;使其运行在双主模式下。 注意…

使用API有效率地管理Dynadot域名,确认域名转移流程状态

关于Dynadot Dynadot是通过ICANN认证的域名注册商&#xff0c;自2002年成立以来&#xff0c;服务于全球108个国家和地区的客户&#xff0c;为数以万计的客户提供简洁&#xff0c;优惠&#xff0c;安全的域名注册以及管理服务。 Dynadot平台操作教程索引&#xff08;包括域名邮…

虚拟网络设备与网络安全:深入分析与实践应用

在数字化时代&#x1f4f2;&#xff0c;网络安全&#x1f512;成为了企业和个人防御体系中不可或缺的一部分。随着网络攻击的日益复杂和频繁&#x1f525;&#xff0c;传统的物理网络安全措施已经无法满足快速发展的需求。虚拟网络设备&#x1f5a7;&#xff0c;作为网络架构中…

k8s集群部署elasticsearch集群和elasticsearch集群设置用户密码

目录 一、背景&#xff1a; 二、部署elasticsearch集群&#xff1a; 1、部署elasticsearch集群&#xff1a; 2、验证elasticsearch集群是否正常&#xff1a; 三、部署elasticsearch集群并设置用户密码 1、生产elastic集群所需的证书&#xff1a; 2、重新建构elasticsearc…

计算机网络——39密钥分发和证书

密钥分发和证书 可信赖中介 对称密钥问题 相互通信的实体如何分享对称密式的密钥&#xff1f; 解决办法 trusted key distribution center(KDC) 在实体之间扮演可信赖中介的角色 公共密钥问题 当Alice获得Bob的公钥(from web site,e-mail,diskette)&#xff0c;她如何知…

16、普通数组-除自身以外的数组乘积

思路 通过辅助数组的方式 第一个从左向右的辅助数组乘积第二次从右向左的辅助数组乘积对于0<i<N-1 他的数组乘积就是左边的数组乘积*右边数组乘积然后再分类讨论i0 就是右边1-N-1的数组乘积iN-1就是左边从N-2到0的数组乘积 代码如下&#xff1a; class Solution {pub…