Golang - 什么是Channel,带缓冲区和不带缓冲区的区别,为什么它可以做到线程安全
Channel的理解
Channel是Go中的一个核心类型,可以把它看成一个管道,通过它并发核心单元就可以发送或者接收数据进行通讯(communication),Channel也可以理解是一个先进先出的队列,通过管道进行通信。
Golang的Channel,发送一个数据到Channel和从Channel接收一个数据都是原子性的。
Go的设计思想就是,不要通过共享内存来通信,而是通过通信来共享内存,前者就是传统的加锁,后者就是Channel。
也就是说,设计Channel的主要目的就是在多任务间传递数据,所以本身就是安全的。
带缓冲区和不带缓冲区的区别
1)缓冲区大小不同
不带缓冲区的chan缓冲区大小是0,带缓冲区的chan缓冲区至少是1
2)运行方式不同
带缓冲区的channel:【同步】
写入阻塞条件:缓冲区满;
取出阻塞条件:缓冲区没有数据。
不带缓冲区的channel:【异步】
写入阻塞条件:同一时间没有另外一个线程对该chan进行读操作;
取出阻塞条件:同一时间没有另外一个线程对该chan进行写操作。
channel存在3种状态
nil:未初始化的状态,只进行了声明,或者手动赋值为nil,nil状态的chan是不能close(panic: close of nil channel);
active:正常的channel,可读或者可写 ;
closed:已关闭,千万不要误认为关闭channel后,channel的值是nil,关闭的状态的chan仍然可以读值(取值),但不能写值(会报panic: send on closed channel)。
func main() {
var a chan int
fmt.Println(a) // <nil>
a = make(chan int)
close(a)
fmt.Println(a) // 0xc00003e060
}
channel可进行3种操作
为什么channel是线程安全?
Channel发送一个数据到Channel和从Channel接收一个数据都是原子性的,核心思想就是:通过通信来共享内存。
1)内置同步机制:
- Channel 在底层实现时使用了锁和其他同步机制来保证并发读写的安全性。
- 在向通道发送或接收数据时,会自动进行加锁和解锁操作,确保每次操作的原子性和线程安全性。
2)阻塞特性:
- 当通道满了(发送者发送数据时),发送操作会阻塞直到有其他 goroutine 从通道中接收数据。
- 当通道为空(接收者尝试接收数据时),接收操作会阻塞直到有其他 goroutine 向通道中发送数据。
- 这种阻塞特性可以有效避免并发读写冲突,保证了数据操作的线程安全性。
3)单个 goroutine 拥有所有权:
Go 语言的设计理念是通过通信来共享内存,而不是通过共享内存来通信。
每个通道只能被一个 goroutine 拥有,并且在同一时间只能由一个 goroutine 发送或接收数据,这种所有权机制确保了通道的线程安全性。
总结
发生 panic 的情况有三种:向一个关闭的 channel 进行写操作;重复关闭一个 channel;关闭一个 nil 的 channel。
发生 阻塞(死锁)的情况:读、写一个 nil的 channel。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析