GO学习之 通道(nil Channel妙用)

GO系列

1、GO学习之Hello World
2、GO学习之入门语法
3、GO学习之切片操作
4、GO学习之 Map 操作
5、GO学习之 结构体 操作
6、GO学习之 通道(Channel)
7、GO学习之 多线程(goroutine)
8、GO学习之 函数(Function)
9、GO学习之 接口(Interface)
10、GO学习之 网络通信(Net/Http)
11、GO学习之 微框架(Gin)
12、GO学习之 数据库(mysql)
13、GO学习之 数据库(Redis)
14、GO学习之 搜索引擎(ElasticSearch)
15、GO学习之 消息队列(Kafka)
16、GO学习之 远程过程调用(RPC)
17、GO学习之 goroutine的调度原理
18、GO学习之 通道(nil Channel妙用)

文章目录

  • GO系列
  • 前言
  • 一、nil channel读写阻塞
  • 二、nil channel 妙用
    • 2.1 一个普通示例
    • 2.2 示例运行分析
    • 2.3 如何妙用 nil channel
  • 三、总结

前言

按照公司目前的任务,go 学习是必经之路了,虽然行业卷,不过技多不压身,依旧努力!!!
在《GO学习之 通道(Channel)》篇中,主要对 Channel 做了简介和用法,主要包含 无缓存通道、有缓存通道 和 单向通道 等,此篇补充一个 nil channel的用法,
看 nil channel 的妙用。

—— 本文内容借鉴《Go语音精进之路》一书。
Go语言精进之路

一、nil channel读写阻塞

对于没有初始化的 channel (nil channel) 进行读写操作会发生阻塞,比如:

package mainfunc main() {var c chan intc <- 1
}

或者

package mainfunc main() {var c chan int<-c
}

无论是上哪段代码,运行都会得到错误的结果, main goroutine 被阻塞在 channel 上,导致 Go 运行时认为出现 deadlock状态并抛出 panic。

PS D:\workspaceGo\src\channel> go run .\nilChannel.go
fatal error: all goroutines are asleep - deadlock!goroutine 1 [chan send (nil chan)]:
main.main()D:/workspaceGo/src/channel/nilChannel.go:5 +0x25
exit status 2

二、nil channel 妙用

2.1 一个普通示例

一般我们在程序中习惯用 channel、goroutine 和 select 来搭配运行,例如:

下面的示例代码中,声明了 c1 c2 两个 channel,并且启动两个 goroutine 向 c1 c2 中延时后添加值,在 for 循环中用 select case 获取到 c1 c2 中的值。

package mainimport ("fmt""time"
)func main() {// 声明 c1 c2 两个通道,并且用 make 函数实例化c1, c2 := make(chan int), make(chan int)go func() {time.Sleep(time.Second * 5)c1 <- 5close(c1)}()go func() {time.Sleep(time.Second * 7)c2 <- 7close(c2)}()var ok1, ok2 boolfor {select {case x := <-c1:ok1 = truefmt.Println(x)case x := <-c2:ok2 = truefmt.Println(x)}if ok1 && ok2 {break}}fmt.Println("program end!")
}

在上面的示例中,我们期望程序在接受完 c1 和 c2 两个 channel 上的数据后就退出,但实际运行结果如下:

PS D:\workspaceGo\src\channel> go run .\nilChannel.go
5
0
0
0
...
7
program end!

期望是程序在输出 5 和 7 之后退出,但实际结果中,输出完 5 之后,程序多输出了几个 0 之后才退出。

2.2 示例运行分析

  1. 程序开始运行,前 5s,select 一直处于阻塞状态。
  2. 第 5s,c1 返回一个 5 后被关闭了,select 语句的 case x := <- c1 分支被执行,程序输出 5,则 for 循环开始新的 select 执行。
  3. c1 已经被关闭,由于从一个已经的关闭的 channel 接受数据将永远不会被阻塞,所以新一轮 select 又将 case x := <- c1 被执行,由于 c1 是关闭状态的,从这个 channel 获取到对于类型的零值,即 0,于是程序输出了 0。所以在 for 循环里面,则一直输出 0 值。
  4. 2s 后,c2 被写入一个数值 7,此时在某一轮循环中,select 则选出 case x: <- c2 并执行。程序输出 7 之后满足条件退出循环,程序终止。

2.3 如何妙用 nil channel

nil channel并非一无是处,nil channel 只要用对了地方,用对了时候,就可以达到事半功倍的效果,将上面的实例程序做了改进,示例代码如下:

package mainimport ("fmt""time"
)func main() {// 声明 c1 c2 两个通道,并且用 make 函数实例化c1, c2 := make(chan int), make(chan int)go func() {time.Sleep(time.Second * 5)c1 <- 5close(c1)}()go func() {time.Sleep(time.Second * 7)c2 <- 7close(c2)}()for {select {case x, ok := <-c1://判断是否获取成功,不成功则把 c1 置为 nilif !ok {c1 = nil} else {fmt.Println(x)}case x, ok := <-c2://判断是否获取成功,不成功则把 c2 置为 nilif !ok {c2 = nil} else {fmt.Println(x)}}if c1 == nil && c2 == nil {break}}fmt.Println("program end!")
}

程序的关键变化在判断 c1 或者 c2被关闭后,显示地把 c1 c2 两个 channel 置为了 nil。
有什么效果呢? 因为 对一个 nil channel 执行获取操作,该操作会被阻塞 ,因此已经被置为 nil 的 c1 c2 再也不会被 select 选中执行了。
运行结果:

PS D:\workspaceGo\src\channel> go run .\nilChannel.go 
5
7
program end!

三、总结

此篇主要在特殊场景下,用了 nil channel 来巧妙的终结了 for select 程序,避免了运行结果的错误,因为 对一个 nil channel 执行获取操作,该操作会被阻塞,但对 一个一个关闭了的 channel 执行获取操作,则会得到 0值

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

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

相关文章

【unity3D】Rect Transform组件

&#x1f497; 未来的游戏开发程序媛&#xff0c;现在的努力学习菜鸡 &#x1f4a6;本专栏是我关于游戏开发的学习笔记 &#x1f236;本篇是unity的Rect Transform组件 Rect Transform组件 基础知识详细介绍补充 基础知识 Rect Transform是Unity中的一个UI组件&#xff0c;用于…

RabbitMQ消费者的可靠性

目录 一、消费者确认 二、失败重试机制 2.1、失败处理策略 三、业务幂等性 3.1、唯一消息ID 3.2、业务判断 3.3、兜底方案 一、消费者确认 RabbitMQ提供了消费者确认机制&#xff08;Consumer Acknowledgement&#xff09;。即&#xff1a;当消费者处理消息结束后&#x…

synchronized 同步锁的思考

经过前面的分析&#xff0c;我们大概对同步锁有了一些基本的认识&#xff0c;同步锁的本质就是实现多线程的互斥&#xff0c;保证同一时刻只有一个线程能够访问加了同步锁的代码&#xff0c;使得线程安全性得到保证。下面我们思考一下&#xff0c;为了达到这个目的&#xff0c;…

Linux 块设备驱动实验

前面我们都是在学习字符设备驱动&#xff0c;本章我们来学习一下块设备驱动框架&#xff0c;块设备驱动是 Linux 三大驱动类型之一。块设备驱动要远比字符设备驱动复杂得多&#xff0c;不同类型的存储设备又 对应不同的驱动子系统&#xff0c;本章我们重点学习一下块设备相关驱…

图像分类任务ViT与CNN谁更胜一筹?DeepMind用实验证明

精华置顶 墙裂推荐&#xff01;小白如何1个月系统学习CV核心知识&#xff1a;链接 点击CV计算机视觉&#xff0c;关注更多CV干货 今天跟大家分享DeepMind发表的一篇技术报告&#xff0c;通过实验得出&#xff0c;CNN与ViT的架构之间虽然存在差异&#xff0c;但同等计算资源的预…

人工智能AI 全栈体系(九)

第一章 神经网络是如何实现的 如何用神经网络处理不等长文本的方法&#xff1f; 八、循环神经网络&#xff08;RNN: Recurrent Neural Network&#xff09; 处理不等长文本的神经网络 – 循环神经网络 RNN。 1. 从句子理解说起 上次讲了用词向量表示词&#xff0c;一句话也…

北邮22级信通院数电:Verilog-FPGA(7)第七周实验(2):BCD七段显示译码器(关注我的uu们加群咯~)

北邮22信通一枚~ 跟随课程进度更新北邮信通院数字系统设计的笔记、代码和文章 持续关注作者 迎接数电实验学习~ 获取更多文章&#xff0c;请访问专栏&#xff1a; 北邮22级信通院数电实验_青山如墨雨如画的博客-CSDN博客 关注作者的uu们可以进群啦~ 目录 一.verilog代码…

Kubernetes Label Selector

Author&#xff1a;rab 目录 前言一、Labels1.1 定义1.2 案例1.2.1 节点标签1.2.2 对象标签 二、Selector2.1 Node Selector2.2 Service Selector2.3 Deployment Selector2.4 StatefulSet Selector2.5 DaemonSet Selector2.6 HorizontalPodAutoscaler Selector2.7 NetworkPolic…

【C】柔性数组

柔性数组 也许你从来没有听说过柔性数组&#xff08;flexible array)这个概念&#xff0c;但是它确实是存在的。 C99 中&#xff0c;结构中的最后一个元素允许是未知大小的数组&#xff0c;这就叫做『柔性数组』成员。 例如&#xff1a; 柔性数组的特点 结构中的柔性数组成员前…

ZKP7.1 Polynomial Commitments Based on Error-correcting Codes (Background)

ZKP学习笔记 ZK-Learning MOOC课程笔记 Lecture 7: Polynomial Commitments Based on Error-correcting Codes (Yupeng Zhang) Recall: common paradigm for efficient SNARK A polynomial commitment scheme A polynomial interactive oracle proof (IOP) SNARK for gene…

CAN总线通信协议

Reference video: 趋近于完美的通讯 CAN总线&#xff01;4分钟看懂&#xff01; CAN通信精华整理&#xff0c;汽车工程师必备技能&#xff0c;一个视频带你轻松掌握&#xff01; 写在前面&#xff1a;CAN通信就三个要点 - 波特率的配置 - 过滤寄存器的配置与理解&#xff08;…

数组与链表算法-单向链表算法

目录 数组与链表算法-单向链表算法 C代码 单向链表插入节点的算法 C代码 单向链表删除节点的算法 C代码 对单向链表进行反转的算法 C代码 单向链表串接的算法 C代码 数组与链表算法-单向链表算法 在C中&#xff0c;若以动态分配产生链表节点的方式&#xff0c;则可以…

“第五十五天”

定点数&#xff1a; 原码的乘法&#xff1a; 乘法的符号位是单独处理的&#xff08;通过对被乘数和乘数的符号位进行异或实现&#xff09;&#xff0c;数值位去绝对值进行运算。这里的乘法实际上是通过多次加法实现的。 这里被乘数是放在x寄存器&#xff0c;乘数放在MQ寄存器…

【音视频|wav】wav音频文件格式详解

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

洛谷 B2009 计算 (a+b)/c 的值 C++代码

目录 题目描述 AC Code 切记 题目描述 题目网址&#xff1a;计算 (ab)/c 的值 - 洛谷 AC Code #include<bits/stdc.h> using namespace std; int main() {int a,b,c;cin>>a>>b>>c;cout<<(ab)/c<<endl;return 0; } 切记 不要复制题…

Netty复习:(2)IdleStateHandler的用法

一、handler定义&#xff1a; package handler;import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter;public class MyChatServerHandler3 extends ChannelInboundHandlerAdapter {Overridepublic void userEventTriggered(…

Pytorch指定数据加载器使用子进程

torch.utils.data.DataLoader(train_dataset, batch_sizebatch_size, shuffleTrue,num_workers4, pin_memoryTrue) num_workers 参数是 DataLoader 类的一个参数&#xff0c;它指定了数据加载器使用的子进程数量。通过增加 num_workers 的数量&#xff0c;可以并行地读取和预处…

分布式:一文吃透分布式锁,Redis/Zookeeper/MySQL实现

目录 一、项目准备spring项目数据库 二、传统锁演示超卖现象使用JVM锁解决超卖解决方案JVM失效场景 使用一个SQL解决超卖使用mysql悲观锁解决超卖使用mysql乐观锁解决超卖四种锁比较Redis乐观锁集成Redis超卖现象redis乐观锁解决超卖 三、分布式锁概述四、Redis分布式锁实现方案…

Linux 文件系统简介

文章目录 一、磁盘简介1.1 简介1.2 机械硬盘与固态硬盘1.2.1 机械磁盘&#xff08;HDD&#xff09;1.2.2 固态磁盘&#xff08;SSD&#xff09;1.2.3 I/O操作 二、文件系统简介2.1. 简介2.2 文件系统特点2.3 Linux文件系统 三、文件数据存储方式3.1 连续存储3.2 链接表存储3.3 …

前端知识与基础应用#2

标签的分类 关于标签我们可以分为 &#xff1a; 单标签&#xff1a;img, br hr 双标签&#xff1a;a&#xff0c;h,div 按照属性可分为&#xff1a; 块儿标签&#xff08;自己独自占一行&#xff09;&#xff1a;h1-h6, p,div 行内&#xff08;内联&#xff09;标签&#xff08…