设为首页收藏本站
网站公告 | 这是第一条公告
     

 找回密码
 立即注册
缓存时间10 现在时间10 缓存数据 大雨过后,彩虹深处,全世界的颜色都在我眼里,全世界的浪漫都在我手心,早安!加油!

大雨过后,彩虹深处,全世界的颜色都在我眼里,全世界的浪漫都在我手心,早安!加油!

查看: 1559|回复: 6

Go语言通道之无缓冲通道与缓冲通道详解

[复制链接]

  离线 

TA的专栏

  • 打卡等级:热心大叔
  • 打卡总天数:220
  • 打卡月天数:0
  • 打卡总奖励:3528
  • 最近打卡:2025-04-11 01:42:35
等级头衔

等級:晓枫资讯-上等兵

在线时间
0 小时

积分成就
威望
0
贡献
395
主题
349
精华
0
金钱
4653
积分
788
注册时间
2023-1-21
最后登录
2025-4-11

发表于 2023-7-25 16:48:22 | 显示全部楼层 |阅读模式
1.通道定义  

在多个协程之间进行通信和管理,可以使用 Go 语言提供的通道(Channel)类型。通道是一种特殊的数据结构,可以在协程之间进行传递数据,从而实现协程之间的通信和同步。多个协程可以同时读写同一个通道,通过通道来进行数据的传递和共享。
通道遵循先入先出(First In First Out)的原则,保证收发数据的顺序。通道是一个特殊的数据类型,在使用之前必须定义和创建通道变量,定义通道的语法如下:
  1. var name chan type
复制代码
语法格式说明如下:
1)var是Go语言关键字,用于定义变量。
2)name是通道变量名称,可自行命名。
3)chan是Go语言关键字,将变量定义为通道类型。
4)type是通道存放的数据类型。
通道定义之后,还需要使用关键字make创建通道,通道的创建语法如下:
  1. name := make(chan type, num)
复制代码
语法格式说明如下:
1)name是通道变量名称,可自行命名。
2)make是Go语言关键字,用于创建通道。
3)chan type的chan是Go语言关键字,type是通道能存放的数据类型。
4)num是通道存放数据的数量上限。
在实际编程中,我们直接使用关键字make创建通道即可使用,这样能省去定义通道的过程,示例代码如下:
  1. // 定义和创建通道
  2.     var ch chan string
  3.     ch = make(chan string)
  4.     // 直接创建通道,无须定义
  5.     ch := make(chan string)
复制代码
通道创建之后,使用通道完成写入和读取数据操作。在通道里面写入和读取数据需要由<-操作符实现,使用说明如下:
  1. // 构建通道
  2.     ch := make(chan string)
  3.     // 往通道写入数据
  4.     ch <- "Hello"
  5.     // 从通道获取数据,赋予变量s
  6.     s := <- ch
复制代码
2.无缓冲通道

无缓冲通道是 Go 语言中一种常见的通道类型,也称为同步通道或阻塞通道。无缓冲通道的特点是在发送和接收数据时,必须有另外一个协程同时进行相反的操作,否则会阻塞当前协程。 具体来说,无缓冲通道的特点如下:

  • 发送和接收操作是同步的,即发送操作必须等待接收操作完成后才能继续执行,接收操作也必须等待发送操作完成后才能继续执行。
  • 无缓冲通道的容量为 0,即只有在发送和接收操作同时进行时才能传递数据,否则会阻塞当前协程。
  • 无缓冲通道的数据传递是按照先进先出的顺序进行的,即发送的数据会按照发送的顺序被接收。 无缓冲通道可以用于协程之间的同步和通信,例如在生产者和消费者模式中,可以使用无缓冲通道来传递数据,从而保证生产者和消费者之间的同步和互斥。同时,无缓冲通道的使用也可以避免数据竞争问题,从而提高程序的安全性和可靠性。
通道是通过关键字make创建的,在创建过程中,如果没有设置参数num,则视为创建无缓冲通道。无缓冲通道(Unbuffered Channel)是指在获取数据之前没有能力保存数据的通道,这种类型的通道要求两个Goroutine同时处于执行状态才能完成写入和获取操作。
如果两个Goroutine没有同时准备,某一个Goroutine执行写入或获取操作将会处于阻塞等待状态,另一个Goroutine无法执行写入或获取操作,程序将会提示异常,这种类型的通道执行写入和获取的交互行为是同步,任意一个操作都无法离开另一个操作单独存在。
当我们使用无缓冲通道的时候,必须注意通道变量的操作,确保程序中有两个或两个以上的Goroutine同时执行通道的读写操作,读写操作必须是一读一写,不能只读不写或只写不读,示例如下:
  1. // 只写入数据,不读取
  2.     ch := make(chan string)
  3.     ch <- "Tom"
  4.     fmt.Println("wait goroutine")
  5.     // 只读取数据,不写入
  6.     ch := make(chan string)
  7.     <- ch
  8.     fmt.Println("wait goroutine")
复制代码
通道数据只写入不读取或者只读取不写入都会提示fatal error: all goroutines are asleep–deadlock异常,如果需要实现通道数据获取超时检测,可以使用关键字select实现。
如果程序中仅有一个Goroutine,使用通道读写数据也会导致异常,比如在主函数main()中对通道写入数据,再读取通道数据,示例如下:
  1. package main
  2.     import (
  3.         "fmt"
  4.     )
  5.     func main() {
  6.         // 构建通道
  7.         ch := make(chan string)
  8.         // 写入通道数据
  9.         ch <- "Tom"
  10.         // 读取通道数据
  11.         <-ch
  12.         fmt.Println("wait goroutine")
  13.     }
复制代码
如果在发送和接收数据时出现异常,则会引发程序异常。例如,如果我们在发送数据之前关闭通道,则会引发一个运行时异常。为了避免这种情况的发生,我们可以使用
  1. defer
复制代码
语句在函数退出之前关闭通道。例如:
  1. func main() {
  2.     ch := make(chan int)
  3.     defer close(ch) // 使用 defer 关闭通道
  4.     go func() {
  5.         fmt.Println("开始发送消息...")
  6.         ch <- 1
  7.         fmt.Println("消息发送完成。")
  8.     }()
  9.     fmt.Println("开始接收消息...")
  10.     msg := <-ch
  11.     fmt.Printf("接收到的消息是:%d\n", msg)
  12.     fmt.Println("消息接收完成。")
  13. }
复制代码
3.带缓冲通道

带缓冲通道(Buffered Channel)是在被获取前能存储一个或者多个数据的通道,这种类型的通道并不强制要求Goroutine之间必须同时完成写入和获取。当通道中没有数据的时候,获取动作才会阻塞;当通道没有可用缓冲区存储数据的时候,写入动作才会阻塞。
在无缓冲通道的基础上,只要为通道增加一个有限大小的存储空间就能形成带缓冲通道。带缓冲通道在写入时无须等待获取即可再次执行下一轮写入,并且不会发生阻塞,只有当存储空间满了才会发生阻塞。同理,如果带缓冲通道中有数据,获取时将不会发生阻塞,直到通道中没有数据可读时,通道才会阻塞。
从通道的定义角度分析,带缓冲和无缓冲通道的区别在于参数num。创建通道的时候,如果没有设置参数num,则默认参数值为0,通道为无缓冲通道,所以写入和获取数据必须同时进行才不会因阻塞而异常;如果参数num大于0,则写入和获取数据无须同步执行,因为通道有足够的空间存放数据。
由于带缓冲通道没有读写同步限制,我们可以在同一个Goroutine中执行多次写入和获取操作,具体示例如下:
  1. package main
  2.     import "fmt"
  3.     func main() {
  4.         // 创建一个3个元素缓冲大小的整型通道
  5.         ch := make(chan int, 3)
  6.         // 查看当前通道的大小
  7.         fmt.Println(len(ch))
  8.         // 发送3个整型元素到通道
  9.         for i := 0; i < 3; i++ {
  10.              ch <- i
  11.         }
  12.         // 查看当前通道的大小
  13.         fmt.Println(len(ch))
  14.         for i := 0; i < 3; i++ {
  15.              fmt.Println(<-ch)
  16.         }
  17.         // 查看当前通道的大小
  18.         fmt.Println(len(ch))
  19.         // 查看当前通道的容量
  20.         fmt.Println(cap(ch))
  21.     }
复制代码
上述代码的说明如下:
1)通过for执行了3次循环,每次循环将变量i写入通道,然后通过3次循环从通道获取数据并输出。
2)通道写入和读取数据的时候,使用len()函数获取通道已有的数据量,判断当前通道存储的数据量是否达到上限,这样可以防止程序在运行时提示异常。
3)使用cap()函数能获取通道的容量大小,即获取创建通道make()的参数num的大小。带缓冲通道在很多特性上和无缓冲通道类似,无缓冲通道可以看作长度为0的带缓冲通道。
根据这个特性,带缓冲通道在下列情况下会发生阻塞:
1)带缓冲通道的存储数据达到上限时,再次写入数据将发生阻塞而导致异常。
2)带缓冲通道没有存储数据时,获取数据将发生阻塞而导致异常。
Go语言为什么对通道要限制长度?因为多个Goroutine之间使用通道必然存在写入和获取操作,这种模式类型的典型例子为生产者消费者模式。如果不限制通道长度,当写入数据速度大于获取速度,内存将不断膨胀直到应用崩溃。因此,限制通道的长度有利于约束数据生产速度,生产数据量必须在数据消费速度+通道长度的范围内,这样才能正常地处理数据。
到此这篇关于Go语言通道之无缓冲通道与缓冲通道详解的文章就介绍到这了,更多相关Go通道内容请搜索晓枫资讯以前的文章或继续浏览下面的相关文章希望大家以后多多支持晓枫资讯!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
      1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
      2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
      3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:点击这里给我发消息进行删除处理。
      4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
      5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
17
积分
14
注册时间
2022-12-27
最后登录
2022-12-27

发表于 2023-7-26 21:47:08 | 显示全部楼层
感谢分享~~~~学习学习~~~~~
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

  • 打卡等级:即来则安
  • 打卡总天数:23
  • 打卡月天数:0
  • 打卡总奖励:295
  • 最近打卡:2025-04-05 05:07:22
等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
340
积分
54
注册时间
2023-1-9
最后登录
2025-4-5

发表于 2023-8-11 07:24:06 | 显示全部楼层
顶顶更健康!!!
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
17
积分
14
注册时间
2022-12-24
最后登录
2022-12-24

发表于 2023-10-15 03:52:56 | 显示全部楼层
感谢楼主分享~~~~~
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
20
积分
20
注册时间
2022-12-29
最后登录
2022-12-29

发表于 2024-10-30 04:25:14 | 显示全部楼层
感谢楼主,顶。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
21
积分
22
注册时间
2022-12-25
最后登录
2022-12-25

发表于 2025-1-1 06:59:33 | 显示全部楼层
感谢楼主分享。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
18
积分
17
注册时间
2022-12-25
最后登录
2022-12-25

发表于 2025-4-7 17:45:09 | 显示全部楼层
路过,支持一下
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~
严禁发布广告,淫秽、色情、赌博、暴力、凶杀、恐怖、间谍及其他违反国家法律法规的内容。!晓枫资讯-社区
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1楼
2楼
3楼
4楼
5楼
6楼
7楼

手机版|晓枫资讯--科技资讯社区 本站已运行

CopyRight © 2022-2025 晓枫资讯--科技资讯社区 ( BBS.yzwlo.com ) . All Rights Reserved .

晓枫资讯--科技资讯社区

本站内容由用户自主分享和转载自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

如有侵权、违反国家法律政策行为,请联系我们,我们会第一时间及时清除和处理! 举报反馈邮箱:点击这里给我发消息

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表