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.mzph.cn/news/124745.shtml

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

相关文章

Vue虚拟DOM理解 | 深入且易懂

文章目录 前言虚拟DOM理解什么是虚拟DOM虚拟DOM转为真实DOM组件的本质模板工作原理 前言 本篇文章部分内容来源于霍春阳 《Vue.js设计与实现》这本书的理解, 感兴趣的小伙伴可以自行购买阅读。可以非常明确的感受到作者对 Vue 的深刻理解以及用心, 富含非常全面的 Vue 的知识点…

面试经典150题——Day26

文章目录 一、题目二、题解 一、题目 392. Is Subsequence Given two strings s and t, return true if s is a subsequence of t, or false otherwise. A subsequence of a string is a new string that is formed from the original string by deleting some (can be none…

Mac电脑Android Studio和VS Code配置Flutter开发环境(图文超详细)

一、安装Android Studio 官网地址&#xff1a; https://developer.android.google.cn/ 历史版本下载地址&#xff1a; https://developer.android.com/studio/archive?hlzh-cn 二、安装Xcode 到App Store下载安装最新版本&#xff0c;如果MacOS更新不到13.0以上就无法安装…

Go-Python-Java-C-LeetCode高分解法-第十二周合集

前言 本题解Go语言部分基于 LeetCode-Go 其他部分基于本人实践学习 个人题解GitHub连接&#xff1a;LeetCode-Go-Python-Java-C 欢迎订阅CSDN专栏&#xff0c;每日一题&#xff0c;和博主一起进步 LeetCode专栏 我搜集到了50道精选题&#xff0c;适合速成概览大部分常用算法 突…

消息中间件——RabbitMQ(一)Windows/Linux环境搭建(完整版)

前言 最近在学习消息中间件——RabbitMQ&#xff0c;打算把这个学习过程记录下来。此章主要介绍环境搭建。此次主要是单机搭建&#xff08;条件有限&#xff09;&#xff0c;包括在Windows、Linux环境下的搭建&#xff0c;以及RabbitMQ的监控平台搭建。 环境准备 在搭建Rabb…

机器人的触发条件有什么区别,如何巧妙的使用

简介​ 维格机器人触发条件,分为3个,分别是: 有新表单提交时、有记录满足条件时、有新的记录创建时 。 看似3个,其实是能够满足我们非常多的使用场景。 本篇将先介绍3个条件的触发条件,然后再列举一些复杂的触发条件如何用现有的触发条件来满足 注意: 维格机器人所有的…

【Python第三方包】串口通信(pySerial包)

文章目录 前言一、串口的基本使用1.1 配置串口基本信息1.2 读取串口数据1.3 写串口1.4 关闭串口二、示例代码2.1 示例1: 从串口读取数据2.2 示例2: 向串口写入数据总结前言 串口通信是许多嵌入式和物联网应用中的关键组成部分。Python 提供了许多第三方库来简化串口通信的实现…

Linux(Centos7)防火墙端口操作记录

1、nginx -t #Nginx配置文件检查 上述截图代表检查没问题 上述截图检查配置文件配置错误&#xff0c;并提示错误文件位置 2、systemctl restart nginx #重启Nginx 重启Nginx失败 3、systemctl status nginx.service #查看Nginx服务状态 80端口被占导致服务启动失败 4、n…

MYSQL(索引篇)

一、什么是索引 索引是一种数据结构&#xff0c;它用来帮助MYSQL更高效的获取数据 采用索引可以提高数据检索的效率&#xff0c;降低IO成本 通过索引对数据排序&#xff0c;降低数据排序成本&#xff0c;降低CPU消耗 常见的有&#xff1a;B树索引、B树索引、哈希索引。其中Inno…

leetcode 238. 除自身以外数组的乘积

leetcode 238. 除自身以外数组的乘积 题目说明&#xff0c;不能使用除法&#xff0c;没有思路。 答案一&#xff1a;超时&#xff0c;因为left、right和result一开始没有设置数组大小&#xff0c;存取浪费时间。 class Solution { public:vector<int> productExceptSel…

【Python】 Python之markdown模块

Python之markdown模块 为了编辑和维护方便使用的是MD来编辑(数据库和文档都是MD)&#xff0c;但是实际展示中生成的API中&#xff0c;需要HTML标签来展示&#xff0c;故此这里需要一个能转换的工具来帮忙。 1. 其他库&#xff1a; markdown markdown2 snudown 2. 安装&…

99%网工都会遇到的经典面试问题

①问题:介绍TCP连接的三次握手?追问:为什么TCP需要握手三次? 三次握手: 第一步:A向B发送一个SYN报文表示希望建立连接 第二步:B收到A发过来的数据包后&#xff0c;通过SYN得知这是一个建立连接的请求&#xff0c;于是发送ACK确认&#xff0c;由于TCP的全双工模式&#xff…

除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂…

代码随想录打卡第五十五天|● 300.最长递增子序列 ● 674. 最长连续递增序列 ● 718. 最长重复子数组

300.最长递增子序列 **题目&#xff1a;**给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长度。子序列 是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的元素而不改变其余元素的顺序。例如&#xff0c;[3,6,2,7] 是数组 [0…

深度学习| U-Net网络

U-Net网络 基础知识和CNN的关系反卷积ReLU激活函数 U-Net入门U-Net网络结构图为什么需要跳跃连接U-Net的输入U-Net的应用 基础知识 理解U-Net网络结构需要相关知识点。 和CNN的关系 U-Net也是CNN&#xff08;Convolutional Neural Network&#xff0c;卷积神经网络&#xff…

Flutter PopupMenuButton下拉菜单

下拉菜单是移动应用交互中一种常见的交互方式,可以使用下拉列表来展示多个内容标签,实现页面引导的作用。在Flutter开发中,实现下拉弹框主要有两种方式,一种是继承Dialog组件使用自定义布局的方式实现,另一种则是使用官方的PopupMenuButton组件进行实现。 如果没有特殊的…

Android任务栈和启动模式

Andrcid中的任务栈是一种用来存放Activity实倒的容器。任务最大的特点就是先进后出&#xff0c;它主要有两个基本操作&#xff0c;分别是压栈和出栈。通常Andaid应用程序都有一个任务栈&#xff0c;每打开一个Activity时&#xff0c;该Activity就会被压入任务栈。每销毁一个Act…

Unity Animator cpu性能测试

测试案例&#xff1a; 场景中共有4000个物体&#xff0c;挂在40个animtor 上&#xff0c;每个Animator控制100个物体的动画。 使用工具&#xff1a; Unity Profiler. Unity 版本&#xff1a; unity 2019.4.40f1 测试环境&#xff1a; 手机 测试过程&#xff1a; 没有挂…

VNC图形化远程连接Ubuntu服务器

我的Ubuntu版本22.04.3&#xff0c;带有gnome图形桌面。配置过程参考了几篇博客&#xff0c;大致流程如下。因为是配置完之后才整理的流程&#xff0c;可能有疏漏。 Ubuntu服务器上的配置 1.先在服务器上下载vnc server&#xff08;任何一种版本均可&#xff09; vncserver有…

新电脑第一次重启后蓝屏

新电脑第一次重启后蓝屏 悲惨事故&#xff0c;远程参加插电第一次开机&#xff0c;按“FNShiftF10”启动cmd窗口输入oobe\bypassnro 回车重启跳过网络连接&#xff0c;设置一个用户名密码设置为空&#xff0c;不设密码确定&#xff0c;进入系统软件操作磁盘操作&#xff08;磁盘…