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

news2025/2/26 2:18:50

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 main

func main() {
	var c chan int
	c <- 1
}

或者

package main

func 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 main

import (
	"fmt"
	"time"
)

func main() {
	// 声明 c1 c2 两个通道,并且用 make 函数实例化
	c1, c2 := make(chan int), make(chan int)

	go func() {
		time.Sleep(time.Second * 5)
		c1 <- 5
		close(c1)
	}()

	go func() {
		time.Sleep(time.Second * 7)
		c2 <- 7
		close(c2)
	}()

	var ok1, ok2 bool
	for {
		select {
		case x := <-c1:
			ok1 = true
			fmt.Println(x)
		case x := <-c2:
			ok2 = true
			fmt.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 main

import (
	"fmt"
	"time"
)

func main() {
	// 声明 c1 c2 两个通道,并且用 make 函数实例化
	c1, c2 := make(chan int), make(chan int)

	go func() {
		time.Sleep(time.Second * 5)
		c1 <- 5
		close(c1)
	}()

	go func() {
		time.Sleep(time.Second * 7)
		c2 <- 7
		close(c2)
	}()

	for {
		select {
		case x, ok := <-c1:
			//判断是否获取成功,不成功则把 c1 置为 nil
			if !ok {
				c1 = nil
			} else {
				fmt.Println(x)
			}
		case x, ok := <-c2:
			//判断是否获取成功,不成功则把 c2 置为 nil
			if !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.coloradmin.cn/o/1148469.html

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

相关文章

网络设备远程登录和管理-双厂商

✍ 设备开局都要做哪些配置&#xff1f; ✍ 思科华为的配置命令有什么区别&#xff1f; ✍ 实战演示不同操作系统的配置&#xff1b; -- 本地设备调试 - console接口配置 -- 远程设备管理 - telnet 不加密 | ssh 加密的 -- web界面调试 - 补充的作用 -- SD…

idea中Run/Debug Python项目报错 Argument for @NotNull parameter ‘module‘ of ...

idea中Run/Debug Python项目报错 Argument for NotNull parameter module of ... idea中运行Python项目main.py时报错&#xff1a; Error running main: Argument for NotNull parameter module of com/intellij/openapi/roots/ModuleRootManager.getInstance must not be nu…

电脑提示由于找不到vcruntime140.dll文件,教你四个解决方案

本文将介绍vcruntime140.dll文件的定义、作用以及丢失的原因&#xff0c;并提供四个解决方案来解决这个问题。 首先&#xff0c;让我们来了解一下vcruntime140.dll文件是什么。vcruntime140.dll是Microsoft Visual C Redistributable Package的一部分&#xff0c;它是运行使用…

从0到1之微信小程序快速入门(基础知识)

目录 JSON 配置文件 WXML 模板 WXSS 样式 JS 逻辑交互 微信小程序中&#xff0c;每个页面由4 个基本文件组成&#xff0c;它们分别是&#xff1a;js文件(页面的脚本文件&#xff0c;存放页面的数据、事件处理函数等)、json文件(当前页面的配置文件&#xff0c;配置窗口的外…

【C++的OpenCV】第十四课-OpenCV基础强化(二):访问单通道Mat中的值之at()、ptr()、iscontinuous()

&#x1f389;&#x1f389;&#x1f389; 欢 迎 各 位 来 到 小 白 p i a o 的 学 习 空 间 &#xff01; \color{red}{欢迎各位来到小白piao的学习空间&#xff01;} 欢迎各位来到小白piao的学习空间&#xff01;&#x1f389;&#x1f389;&#x1f389; &#x1f496;&…

Python——新建工程/引入本地库

文章目录 前言一、创建项目及文件二、之前创建项目未勾选Inherit global site-packages三、缺少第三方库报错pywpswin32commarkupsafe前言 PyCharm是一种Python IDE(Integrated Development Environment,集成开发环境),带有一整套可以帮助用户在使用Python语言开发时提高其…

【论文解读】单目3D目标检测 LPCG(ECCV 2022)

本文分享单目3D目标检测&#xff0c;LPCG模型的论文解读&#xff0c;了解它的设计思路&#xff0c;论文核心观点&#xff0c;模型结构&#xff0c;以及效果和性能。 目录 一、LPCG 简介 二、论文核心观点 三、思路框架 四、核心观点——单目3D目标检测的标签中&#xff0c;…

MySQL数据库 #5

文章目录 一、Python操作MySQL1.pymysql的基本操作2.pymysql补充说明1.查看补充2. 增删改&#xff0c;自动确认 3.SQL注入问题1.输入对的用户名就可登录2.输入错的用户名也可以登录针对上述的SQL注入问题&#xff0c;核心在于手动拼接了关键数据 二、视图1.什么是视图2. 为什么…

RPC与HTTP的关系

首选理清楚关系 RPC与HTTP是两个不同维度的东西 HTTP 协议&#xff08;Hyper Text Transfer Protocol&#xff09;&#xff0c;又叫做超文本传输协议&#xff0c;是一种传输协议&#xff0c;平时通过浏览器浏览网页网页&#xff0c;用到的就是 HTTP 协议。 而 RPC&#xff0…

全能数字音乐工作站(DAW)编曲FL Studio21.2.0官方中文版

FL Studio21.2.0官方中文版重磅发布纯正简体中文支持&#xff0c;更快捷的音频剪辑及素材管理器&#xff0c;多样主题随心换&#xff01;Mac版新增对苹果M2/1家族芯片原生支持。全能数字音乐工作站&#xff08;DAW&#xff09;编曲、剪辑、录音、混音&#xff0c;26余年的技术积…

LeetCode题:88合并两个有序数组,283移动零,448找到所有数组中消失的数字

目录 88合并两个有序数组 1、题目要求 2、解题思路 &#xff08;1&#xff09;、暴力解法&#xff1a; &#xff08;2&#xff09;、双指针&#xff0c;使用第三数组的解法&#xff1a; 3、代码展示 &#xff08;1&#xff09;、暴力解法&#xff1a; &#xff08;2&am…

ITSource 分享 第6期【网址云收藏系统】

项目介绍 本期给大家介绍一个 网址云收藏系统.。 你是否因为上网过程中收藏了很多网址找不到而发愁&#xff0c;如果浏览器没有登录账号开启同步的情况下&#xff0c;换个电脑&#xff0c;换个浏览器&#xff0c;以前收藏的网址就找不到了。 本期给大家推荐一个可以在线随时随地…

jmeter BeanShell预处理程序:报错Error invoking bsh method: eval...

1、jmeter运行报错&#xff1a; ERROR o.a.j.u.BeanShellInterpreter: Error invoking bsh method: eval In file: inline evaluation of: " . . . Encountered "" at line 13, column 23. WARN o.a.j.m.BeanShellPreProcessor: Problem in BeanShell scri…

[毕设记录]@学术技能积累:学位论文查询与下载

文章目录 ProQuest国外学位论文中国集团全文检索平台OATD.org&#xff08;Open Access Theses and Dissertations&#xff09;DART-EuropeTUDelft 在上一篇blog里面看的那些论文&#xff0c;感觉看起来收获太小了… 不如去看硕士或者博士的学位论文 于是我先去调研一下哪里方便…

如何将SAP数据集成到任意云平台

十年前就在使用SAP的客户询问我当时突然出现的新事物&#xff1a;大数据。五年前&#xff0c;变成了数据湖和机器学习。现在一切都是关于数据集成&#xff0c;当然还有人工智能。有时处理数据的基本方法已经改变或者发展。有时只是名字的改变。例如&#xff0c;在过去十年中&am…

测试大佬的压箱绝技:教你app 自动化测试如何实现多设备并发

appiumpython appiumpython 实现单设备的 app 自动化测试 启动 appium server&#xff0c;占用端口 4723 电脑与一个设备连接&#xff0c;通过 adb devices 获取已连接的设备 在 python 代码当中&#xff0c;编写启动参数&#xff0c;通过 pytest 编写测试用例&#xff0c;来…

代码审计-锐捷EG易网关 cli.php 远程命令执行

首先登录到后台中(可以组合 锐捷EG易网关 管理员账号密码泄露漏洞) 关键部分代码为 使用 exec 函数执行传递的命令 构造payload&#xff1a; /cli.php?ashell notdelaytrue&commandid漏洞证明&#xff1a; 文笔生疏&#xff0c;措辞浅薄&#xff0c;望各位大佬不吝赐教…

【C语言】内存的动态分配与释放

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:C语言 ⚙️操作环境:Visual Studio 2022 ​ 目录 什么是内存的动态分配? 内存动态分配函数 &#x1f38f;malloc() &#x1f38f;calloc() &#x1f38f;realloc() 动态内存释放函数 &#x1f38f;free() 常见的…

轻量封装WebGPU渲染系统示例<5>-多重纹理(源码)

当前示例源码github地址: https://github.com/vilyLei/voxwebgpu/blob/version-1.01/src/voxgpu/sample/MultiTexturedCube.ts 此示例渲染系统实现的特性: 1. 用户态与系统态隔离。 2. 高频调用与低频调用隔离。 3. 面向用户的易用性封装。 4. 渲染数据和渲染机制分离。 …

【2023Mathorcup大数据】B题 电商零售商家需求预测及库存优化问题 python代码解析

【2023Mathorcup大数据】B题 电商零售商家需求预测及库存优化问题 python代码解析 1 题目 2023 年MathorCup 高校数学建模挑战赛——大数据竞赛赛道B&#xff1a;电商零售商家需求预测及库存优化问题电商平台存在着上千个商家&#xff0c;他们会将商品货物放在电商配套的仓库…