当前聚焦:GO通道:无缓冲通道与缓冲通道
转载请注明出处:
(资料图片仅供参考)
1.通道定义在多个协程之间进行通信和管理,可以使用 Go 语言提供的通道(Channel)类型。通道是一种特殊的数据结构,可以在协程之间进行传递数据,从而实现协程之间的通信和同步。多个协程可以同时读写同一个通道,通过通道来进行数据的传递和共享。
通道遵循先入先出(First In First Out)的原则,保证收发数据的顺序。通道是一个特殊的数据类型,在使用之前必须定义和创建通道变量,定义通道的语法如下:
var name chan type
语法格式说明如下:
1)var是Go语言关键字,用于定义变量。
2)name是通道变量名称,可自行命名。
3)chan是Go语言关键字,将变量定义为通道类型。
4)type是通道存放的数据类型。
通道定义之后,还需要使用关键字make创建通道,通道的创建语法如下:
name := make(chan type, num)
语法格式说明如下:
1)name是通道变量名称,可自行命名。
2)make是Go语言关键字,用于创建通道。
3)chan type的chan是Go语言关键字,type是通道能存放的数据类型。
4)num是通道存放数据的数量上限。
在实际编程中,我们直接使用关键字make创建通道即可使用,这样能省去定义通道的过程,示例代码如下:
// 定义和创建通道 var ch chan string ch = make(chan string) // 直接创建通道,无须定义 ch := make(chan string)
通道创建之后,使用通道完成写入和读取数据操作。在通道里面写入和读取数据需要由<-操作符实现,使用说明如下:
// 构建通道 ch := make(chan string) // 往通道写入数据 ch <- "Hello" // 从通道获取数据,赋予变量s s := <- ch2.无缓冲通道
无缓冲通道是 Go 语言中一种常见的通道类型,也称为同步通道或阻塞通道。无缓冲通道的特点是在发送和接收数据时,必须有另外一个协程同时进行相反的操作,否则会阻塞当前协程。 具体来说,无缓冲通道的特点如下:
发送和接收操作是同步的,即发送操作必须等待接收操作完成后才能继续执行,接收操作也必须等待发送操作完成后才能继续执行。
无缓冲通道的容量为 0,即只有在发送和接收操作同时进行时才能传递数据,否则会阻塞当前协程。
无缓冲通道的数据传递是按照先进先出的顺序进行的,即发送的数据会按照发送的顺序被接收。 无缓冲通道可以用于协程之间的同步和通信,例如在生产者和消费者模式中,可以使用无缓冲通道来传递数据,从而保证生产者和消费者之间的同步和互斥。同时,无缓冲通道的使用也可以避免数据竞争问题,从而提高程序的安全性和可靠性。
通道是通过关键字make创建的,在创建过程中,如果没有设置参数num,则视为创建无缓冲通道。无缓冲通道(Unbuffered Channel)是指在获取数据之前没有能力保存数据的通道,这种类型的通道要求两个Goroutine同时处于执行状态才能完成写入和获取操作。
如果两个Goroutine没有同时准备,某一个Goroutine执行写入或获取操作将会处于阻塞等待状态,另一个Goroutine无法执行写入或获取操作,程序将会提示异常,这种类型的通道执行写入和获取的交互行为是同步,任意一个操作都无法离开另一个操作单独存在。
当我们使用无缓冲通道的时候,必须注意通道变量的操作,确保程序中有两个或两个以上的Goroutine同时执行通道的读写操作,读写操作必须是一读一写,不能只读不写或只写不读,示例如下:
// 只写入数据,不读取 ch := make(chan string) ch <- "Tom" fmt.Println("wait goroutine") // 只读取数据,不写入 ch := make(chan string) <- ch fmt.Println("wait goroutine")
通道数据只写入不读取或者只读取不写入都会提示fatal error: all goroutines are asleep–deadlock异常,如果需要实现通道数据获取超时检测,可以使用关键字select实现。
如果程序中仅有一个Goroutine,使用通道读写数据也会导致异常,比如在主函数main()中对通道写入数据,再读取通道数据,示例如下:
package main import ( "fmt" ) func main() { // 构建通道 ch := make(chan string) // 写入通道数据 ch <- "Tom" // 读取通道数据 <-ch fmt.Println("wait goroutine") }
如果在发送和接收数据时出现异常,则会引发程序异常。例如,如果我们在发送数据之前关闭通道,则会引发一个运行时异常。为了避免这种情况的发生,我们可以使用 defer
语句在函数退出之前关闭通道。例如:
func main() { ch := make(chan int) defer close(ch) // 使用 defer 关闭通道 go func() { fmt.Println("开始发送消息...") ch <- 1 fmt.Println("消息发送完成。") }() fmt.Println("开始接收消息...") msg := <-ch fmt.Printf("接收到的消息是:%d\n", msg) fmt.Println("消息接收完成。")}3.带缓冲通道
带缓冲通道(Buffered Channel)是在被获取前能存储一个或者多个数据的通道,这种类型的通道并不强制要求Goroutine之间必须同时完成写入和获取。当通道中没有数据的时候,获取动作才会阻塞;当通道没有可用缓冲区存储数据的时候,写入动作才会阻塞。
在无缓冲通道的基础上,只要为通道增加一个有限大小的存储空间就能形成带缓冲通道。带缓冲通道在写入时无须等待获取即可再次执行下一轮写入,并且不会发生阻塞,只有当存储空间满了才会发生阻塞。同理,如果带缓冲通道中有数据,获取时将不会发生阻塞,直到通道中没有数据可读时,通道才会阻塞。
从通道的定义角度分析,带缓冲和无缓冲通道的区别在于参数num。创建通道的时候,如果没有设置参数num,则默认参数值为0,通道为无缓冲通道,所以写入和获取数据必须同时进行才不会因阻塞而异常;如果参数num大于0,则写入和获取数据无须同步执行,因为通道有足够的空间存放数据。
由于带缓冲通道没有读写同步限制,我们可以在同一个Goroutine中执行多次写入和获取操作,具体示例如下:
package main import "fmt" func main() { // 创建一个3个元素缓冲大小的整型通道 ch := make(chan int, 3) // 查看当前通道的大小 fmt.Println(len(ch)) // 发送3个整型元素到通道 for i := 0; i < 3; i++ { ch <- i } // 查看当前通道的大小 fmt.Println(len(ch)) for i := 0; i < 3; i++ { fmt.Println(<-ch) } // 查看当前通道的大小 fmt.Println(len(ch)) // 查看当前通道的容量 fmt.Println(cap(ch)) }
上述代码的说明如下:
1)通过for执行了3次循环,每次循环将变量i写入通道,然后通过3次循环从通道获取数据并输出。
2)通道写入和读取数据的时候,使用len()函数获取通道已有的数据量,判断当前通道存储的数据量是否达到上限,这样可以防止程序在运行时提示异常。
3)使用cap()函数能获取通道的容量大小,即获取创建通道make()的参数num的大小。带缓冲通道在很多特性上和无缓冲通道类似,无缓冲通道可以看作长度为0的带缓冲通道。
根据这个特性,带缓冲通道在下列情况下会发生阻塞:
1)带缓冲通道的存储数据达到上限时,再次写入数据将发生阻塞而导致异常。
2)带缓冲通道没有存储数据时,获取数据将发生阻塞而导致异常。
Go语言为什么对通道要限制长度?因为多个Goroutine之间使用通道必然存在写入和获取操作,这种模式类型的典型例子为生产者消费者模式。如果不限制通道长度,当写入数据速度大于获取速度,内存将不断膨胀直到应用崩溃。因此,限制通道的长度有利于约束数据生产速度,生产数据量必须在数据消费速度+通道长度的范围内,这样才能正常地处理数据。
关键词:
下一篇:最后一页
- 广州科技活动周进入预热 明日正式启动300多场主题活动接踵而来
- 深化重点领域信用建设 广州正式出台新型监管机制实施方案
- 女童不慎掉入20米深井 18岁小姨三次下井成功营救
- 西安3个区域12月28日起每日开展全员核酸 官方提倡民众居家健身
- 浙江乐清一核酸检测结果异常人员 复采复检为阴性
- 浙江本轮疫情报告确诊病例490例 提倡“双节”非必要不出省
- 西安警方通报6起涉疫违法案件
- 西安新一轮核酸筛查日检测能力达160万管
- 西安市累计报告本土确诊病例811例
- 重庆曝光4起违反中央八项规定精神典型问题 警示党员干部清新过节
-
建筑节能工程监理质量控制手册
1、《建筑节能工程监理质量控制手册》是中国建筑工业出版社出版的图书
-
世界最新:演讲与口才:全球最振奋精英演讲
1、《演讲与口才:全球最振奋精英演讲(中英对照)》。本文关于演讲与口
-
速递!我国三北防护林实现“绿进沙退”历史性转变
防沙治沙离不开重大林业生态工程,三北防护林建设工程是世界最大的林业
-
最新资讯:路遥的人生听书_路遥的人生
1、路遥的一部《人生》不但给我们展现了主人公高加林曲折、起伏的人生
-
【长测】华为WATCH FIT 2运动体验:挥洒汗水,结交挚友 全球热文
在去年的华为nova10系列及全场景新品夏季发布会上,大家期待已久的华为
-
淘宝支付宝首页变黑白,淘宝支付宝首页变黑白怎么设置
本文内容是由小编为大家搜集关于淘宝支付宝首页变黑白,以及淘宝支付宝
-
江西爱可信电子商务有限公司_关于江西爱可信电子商务有限公司简述|环球观点
1、江西爱可信电子商务有限公司于2015年03月24日成立。2、法定代表人许
-
牧马人柴油多久保养一次好(牧马人柴油多久保养一次?)
牧马人(参数|询价)柴油1万公里保养一次,牧马人是一款中型suv,该车长
-
新天龙八部视角改了怎么没用_新天龙八部视角包下载 世界快看
1、你说的视角跳远么找到文件夹有个BIN文件里面有个ST什么的文件点开有
-
戚继光舰结束对菲律宾友好访问起程回国
今天(6月17日)上午,海军戚继光舰圆满结束对菲律宾友好访问,驶离马
X 关闭
当前聚焦:GO通道:无缓冲通道与缓冲通道
“郑洁杯”青少年网球巡回赛北京开拍
全球观天下!alx-al10_alx
罗马诺:坎特已完成最后一部分体检,交易将在未来几小时宣布
天天快报!荣耀Magic5 至臻版PWM调光多少
X 关闭
焦点讯息:水发燃气董秘回复:根据《上海证券交易所股票上市规则》的规定
西安警方完成研考安保工作 共出动警力逾1.3万人次
得知西安疫情防控“升级” 男子夜骑共享单车回咸阳淳化
中国医生将任SIU主席背后:从追随者同行者到引领者
海南省通报政法队伍教育整顿成果