GO学习之 通道(Channel)

news/2024/4/23 20:47:22/文章来源:https://blog.csdn.net/qq_19283249/article/details/131993360

GO系列

1、GO学习之Hello World
2、GO学习之入门语法
3、GO学习之切片操作
4、GO学习之 Map 操作
5、GO学习之 结构体 操作
6、GO学习之 通道(Channel)

文章目录

  • GO系列
  • 前言
  • 一、Channel 简介
  • 二、初始化通道
    • 2.1 无缓冲通道
    • 2.2 有缓冲通道
    • 2.3 单向通道
  • 三、通道操作
    • 3.1 关闭通道
  • 四、通道异常情况
  • 五、总结

前言

按照公司目前的任务,go 学习是必经之路了,虽然行业卷,不过技多不压身,依旧努力!!!
现在的互联网项目中,并发量是衡量一个项目的相当重要的指标,如果一个项目不能支持高并发,就好像一辆超跑用了一缸发动机,中看不中用,一点意义都没有啊。
那怎么支持高并发呢,首当其冲的肯定是多线程了,那多线程就势必会带来一个问题,数据的同步和安全!
当然此篇不说多线程,先说说支持多线程之间数据同步的 Channel。
虽然可以用共享内存进行数据交互,但是共享内存在不同的 goroutine 中很容易发生资源竞争的问题,所以为了保证数据交互的正确性,必须使用锁对内存进行加锁,但是这种做法就会带来性能问题了。
Go 语言的并发模型是 CSP(Communicating Sequential Processes),提倡通过通信共享内存实现线程间的数据交互。

一、Channel 简介

Go 语言中的通道(Channel)是一种特殊的类型。见名知意,一边进来另一边出去,或者说通道就像一个队列,总是遵循 先入后出(First In Frist Out) 的规则,以便能保证顺序。
每个通道都是一个具体类型的管道,也就是在声明的时候需要指定元素的数据类型一样。

二、初始化通道

Channel 是一种引用类型,声明通道类型的格式如下:

var 变量名 chan 元素类型

package mainimport "fmt"func main() {// 声明一个空的channelvar ch1 chan intfmt.Printf("初始化ch1: %+v\n", ch1)ch1 <- 1ch1 <- 2ch1 <- 3fmt.Printf("%+v\n", ch1)
}

运行结果:

PS D:\workspaceGo> go run channelTest.go
初始化ch1: <nil>
fatal error: all goroutines are asleep - deadlock!goroutine 1 [chan send (nil chan)]:
main.main()D:/workspaceGo/channelTest.go:9 +0x73
exit status 2

在声明后的 ch1 接受元素是报错了,因为我们声明的 ch1 其实是一个 nil,向一个空的channel发送元素则会报错。
声明的通道需要使用 make() 函数初始化之后才能使用。

2.1 无缓冲通道

package mainimport "fmt"func main() {// 声明并且初始化channelch1 := make(chan int)fmt.Printf("初始化ch1: %+v\n", ch1)ch1 <- 1
}

运行结果:

PS D:\workspaceGo> go run channelTest.go
初始化ch1: 0xc0000220c0
fatal error: all goroutines are asleep - deadlock!goroutine 1 [chan send]:
main.main()D:/workspaceGo/channelTest.go:9 +0x85
exit status 2

这里为什么会出现 deadlock 错误呢?
答:因为我们创建的是无缓冲通道,无缓冲的通道只有在有其他地方接受值的情况下才能发送值。上面的示例中阻塞在 ch1 <- 1 形成死锁,如何解决呢?我们可以用另一个 goroutine 去接受值,如下:

package mainimport "fmt"func main() {// 声明并且初始化channelch1 := make(chan int)// 启动一个 gorountine从通道接收值go receive(ch1)ch1 <- 1ch1 <- 2ch1 <- 3fmt.Println("发送完成!")
}func receive(c chan int) {for i := 0; i < 5; i++ {r := <-cfmt.Printf("接收到的值为:%+v\n", r)}
}

运行结果:

PS D:\workspaceGo> go run channelTest.go
接收到的值为:1
接收到的值为:2
接收到的值为:3
发送完成!

在这个示例中,单独启动一个 goruntine来循环从 ch1 通道中获取值,这样就可以通过 ch1 <- * 不断的往里面放值了。

2.2 有缓冲通道

可以在 make() 函数初始化通道的时候为其指定通道的容量,如下:

package mainimport ("fmt""time"
)func main() {// 声明并且初始化channelch1 := make(chan int, 5)go receive(ch1)for i := 0; i < 10; i++ {fmt.Printf("向ch1中发送 %d 个元素 \n", i)ch1 <- i}fmt.Println("发送完成!")ch1 <- 6
}func receive(c chan int) {for i := 0; i < 10; i++ {time.Sleep(time.Second * 3)r := <-cfmt.Printf("接收到的值为:%+v\n", r)}
}

运行结果:

PS D:\workspaceGo> go run channelTest.go
向ch1中发送 0 个元素 
向ch1中发送 1 个元素
向ch1中发送 2 个元素
向ch1中发送 3 个元素
向ch1中发送 4 个元素
向ch1中发送 5 个元素
接收到的值为:0
向ch1中发送 6 个元素
接收到的值为:1
向ch1中发送 7 个元素
接收到的值为:2
向ch1中发送 8 个元素
接收到的值为:3
向ch1中发送 9 个元素
接收到的值为:4
发送完成!

初始化通道是制定缓存数量,可以往通道中放入初始化数量以内个数的元素,但是超过了初始化量则会阻塞,等通道中空闲出来

2.3 单向通道

三、通道操作

通道有三种操作:

  • 发送:上面例子中已包含
  • 接受:上面例子中已包含
  • 关闭

3.1 关闭通道

可以通过 close() 函数来关闭 channel(对通道的发送和接受完毕,记得关闭通道),如下:

package main
import ("fmt"
)
func main() {// 声明并且初始化channelch1 := make(chan int, 1)go receive(ch1)for i := 0; i < 5; i++ {fmt.Printf("向ch1中发送 %d 个元素 \n", i)ch1 <- i}fmt.Println("发送完成!")// 关闭通道close(ch1)
}
func receive(c chan int) {for i := 0; i < 10; i++ {r, ok := <-cif !ok {fmt.Printf("接收到的值为:%+v\n", r)} else {fmt.Println("通道已关闭!")}}
}

运行结果:

PS D:\workspaceGo> go run channelTest.go
向ch1中发送 0 个元素 
向ch1中发送 1 个元素
通道已关闭!
向ch1中发送 2 个元素
通道已关闭!
向ch1中发送 3 个元素
通道已关闭!
向ch1中发送 4 个元素
通道已关闭!
发送完成!

初始化通道,缓冲为 1 ,当向 ch1 通道中发送元素后,就立马关闭 通道,在 receive() 函数中只能接受到部分元素。

四、通道异常情况

操作nil非空没满
接受deadlock接受成功阻塞接受成功接受成功
发送deadlock发送成功发送成功阻塞发送成功
关闭panic关闭成功,关闭后,接受到 0 值关闭成功,接收到 0 值关闭成功,接受到0值关闭成功,接受到0值

五、总结

通道(Channel)基本的初始化和发送、接受、关闭等操作基本在此篇中体现,使用起来还是间接明了。不像 Java 还需要利用一下锁去控制线程之间的安全问题,虽说是对多线程有较好的支持,但是线程间的数据共享确实实现比较复杂,运用也不简单,需要去深挖。
现阶段还是对 Go 语言的学习阶段,想必有一些地方考虑的不全面,本文示例全部是亲自手敲代码并且执行通过,如有问题,还请指教。
评论去告诉我哦!!!一起学习一起进步!!!

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

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

相关文章

大数据-Spark批处理实用广播Broadcast构建一个全局缓存Cache

1、broadcast广播 在Spark中&#xff0c;broadcast是一种优化技术&#xff0c;它可以将一个只读变量缓存到每个节点上&#xff0c;以便在执行任务时使用。这样可以避免在每个任务中重复传输数据。 2、构建缓存 import org.apache.spark.sql.SparkSession import org.apache.s…

WIZnet W5500-EVB-Pico 静态IP配置教程(二)

W5500是一款高性价比的 以太网芯片&#xff0c;其全球独一无二的全硬件TCP、IP协议栈专利技术&#xff0c;解决了嵌入式以太网的接入问题&#xff0c;简单易用&#xff0c;安全稳定&#xff0c;是物联网设备的首选解决方案。WIZnet提供完善的配套资料以及实时周到的技术支持服务…

解决mysqld服务启动失败

原因如下&#xff1a; 1、进程占用 首先查看下mysql进程: ps -aux | grep mysql有进程号占用了&#xff0c;kill 这个进程号 再重启服务 2、所有者和所属组为mysql 查看/usr/local/MySQL/data/mysqld.pid所有者和所属组是否为mysql 原来是权限有问题&#xff0c…

TPlink云路由器界面端口映射设置方法?快解析内网穿透能实现吗?

有很多网友在问&#xff1a;TPlink路由器端口映射怎么设置&#xff1f;因为不懂端口映射的原理&#xff0c;所以无从下手&#xff0c;下面小编就给大家分享TPlink云路由器界面端口映射设置方法&#xff0c;帮助大家快速入门TP路由器端口映射设置方法。 1.登录路由器管理界面&a…

MySQL中锁的简介——表级锁-元数据锁、意向锁

1.元数据锁 查看元数据锁 select object_type,object_scheme,object_name,lock_type,lock_duration from perfomance_scheme.metadata_locks;2.意向锁 线程A开启事务后在执行update更新语句时候&#xff0c;会给数据加上行锁&#xff0c;加上行锁以后&#xff0c;会对整张表加…

回归预测 | MATLAB实现WOA-ELM鲸鱼算法优化极限学习机多输入单输出回归预测

回归预测 | MATLAB实现WOA-ELM鲸鱼算法优化极限学习机多输入单输出回归预测 目录 回归预测 | MATLAB实现WOA-ELM鲸鱼算法优化极限学习机多输入单输出回归预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 Matlab实现WOA-ELM鲸鱼算法优化极限学习机多输入回归预测&#…

35.图片幻灯片

图片幻灯片 html部分 <div class"carousel"><div class"image-container"><img src"./static/20180529205331_yhGyf.jpeg" alt"" srcset""><img src"./static/20190214214253_hsjqw.webp"…

【已解决】电脑连上网线但无法上网

文章目录 案例情况解决方案必要的解决方法简要概括详细步骤1、打开控制面板2、打开更改适配器设置3、 找Internet协议版本44、修改配置 可能有用的解决方法 问题解决原理Internet 协议版本 4&#xff08;TCP/IPv4&#xff09;确保IP地址和DNS服务器设置为自动获取 案例情况 网…

基于正交滤波器组的语音DPCM编解码算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 ...........................................................g0zeros(1,lenH); g1zeros(1,l…

基于51单片机和proteus的加热洗手器系统设计

此系统是基于51单片机和proteus的仿真设计&#xff0c;功能如下&#xff1a; 1. 检测到人手后开启出水及加热。 2. LED指示加热出水及系统运行状态。 功能框图如下&#xff1a; Proteus仿真界面如下&#xff1a; 下面就各个模块逐一介绍&#xff0c; 模拟人手检测模块 通过…

MongoDB的安装(详细教程)

文章目录 前言一、概述二、下载三、安装与启动四、连接1. Shell 命令连接1. Compass-图形化界面客户端 前言 MongoDB 是一个基于分布式文件存储的数据库&#xff0c;主要用于为 web 应用提供可扩展的高性能数据存储解决方案。 以下内容是如何在 windows 下安装 MongoDB 的教程…

github Recv failure: Connection reset by peer

Recv failure: Connection reset by peer 背景处理ping一下github网页访问一下github项目git配置git ssh配置再次尝试拉取 疑惑点待研究参考 背景 晚上敲着代码准备提交&#xff0c;执行git pull&#xff0c;报错Recv failure: Connection reset by peer。看着这报错我陷入了沉…

EMO:重新思考高效的基于注意力的移动块模型

文章目录 摘要1、介绍2、方法论:归纳法和演绎法2.1、通用效率模型标准2.2、元移动块2.3、微设计:倒置残余移动块2.4、面向密集预测的EMO宏观设计 3、实验3.1、图像分类3.2、下游任务3.3、额外的消融和解释分析 4、相关工作5、结束语及未来工作 摘要 论文链接&#xff1a;https…

Linux安装MySQL 8.1.0

MySQL是一个流行的开源关系型数据库管理系统&#xff0c;本教程将向您展示如何在Linux系统上安装MySQL 8.1.0版本。请按照以下步骤进行操作&#xff1a; 1. 下载MySQL安装包 首先&#xff0c;从MySQL官方网站或镜像站点下载MySQL 8.1.0的压缩包mysql-8.1.0-linux-glibc2.28-x…

机器学习:提取问题答案

模型BERT 任务&#xff1a;提取问题和答案 问题的起始位置和结束位置。 数据集 数据集 DRCDODSQA 先分词&#xff0c;然后tokenize 文章长度是不同的&#xff0c;bert的token的长度有限制&#xff0c;一般是512&#xff0c; self-attention的计算量是 O ( n 2 ) O(n^2) O(n…

vo 2 输出helloworld

vo 2 输出helloworld 目录概述需求&#xff1a; 设计思路实现思路分析1.code 拓展实现性能参数测试&#xff1a; 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a better r…

NoSQL-Redis集群

NoSQL-Redis集群 一、集群&#xff1a;1.单点Redis带来的问题&#xff1a;2.解决&#xff1a;3.集群的介绍&#xff1a;4.集群的优势&#xff1a;5.集群的实现方式&#xff1a; 二、集群的模式&#xff1a;1.类型&#xff1a;2.主从复制&#xff1a; 三、搭建主从复制&#xff…

[个人笔记] vCenter设置时区和NTP同步

VMware虚拟化 - 运维篇 第三章 vCenter设置时区和NTP同步 VMware虚拟化 - 运维篇系列文章回顾vCenter设置时区和NTP同步&#xff08;附加&#xff09;ESXi设置alias参考链接 系列文章回顾 第一章 vCenter给虚机添加RDM磁盘 第二章 vCenter回收活跃虚拟机的剩余可用空间 vCente…

【算法基础:动态规划】5.4 数位统计DP(计数问题)(数位DP)

文章目录 例题&#xff1a;338. 计数问题解法1——转换成1067. 范围内的数字计数&#xff0c;数位DP模板解法2——分情况讨论&#xff08;TODO&#xff0c;还没理解&#xff09; 相关链接⭐ 例题&#xff1a;338. 计数问题 https://www.acwing.com/problem/content/340/ 解法…

软考A计划-系统集成项目管理工程师-项目人力资源管理-中

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff…