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是不能closepanic: 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。 

对未初始化的的chan进行读(接收)写(发送),会怎么样?为什么?【查看原文

对已经关闭的chan进行读写,会怎么样?为什么?【查看原文

posted @   李若盛开  阅读(917)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
点击右上角即可分享
微信分享提示