0%

go语言基础4——Channel相关

channel 是否线程安全?锁用在什么地方?

Golang的Channel,发送一个数据到Channel 和 从Channel接收一个数据都是原子性的。

如果把线程安全定义为允许多个goroutine同时去读写,那么golang 的channel 是线程安全的,因为channel底层数据结构中是带有lock的,不需要在并发读写同一个channe时再加锁。

而且Go的设计思想就是:不要通过共享内存来通信,而是通过通信来共享内存,前者就是传统的加锁(共享内存通信),后者就是Channel。

也就是说,设计Channel的主要目的就是在多任务间传递数据的,这当然是安全的

go channel 的底层实现原理 (数据结构)

总结hchan结构体的主要组成部分有四个:

  • 用来保存goroutine之间传递数据的循环数组:buf
  • 用来记录此循环数组当前发送或接收数据的下标值:sendx(发送队列)和recvx(接受队列)
  • 用于保存向该chan发送和从该chan接收数据被阻塞的goroutine队列: sendq 和 recvq
  • 保证channel写入和读取数据时线程安全的锁:lock
go channel为什么设计成线程安全?

不同协程通过channel进行通信,本身的使用场景就是多线程,为了保证数据的一致性,必须实现线程安全

如何实现线程安全的?

channel的底层实现中,hchan结构体中采用Mutex(互斥)锁来保证数据读写安全。在对循环数组buf中的数据进行入队和出队操作时,必须先获取互斥锁,才能操作channel数据

nil、关闭的 channel、有数据的 channel,再进行读、写、关闭会怎么样?
  1. 读写值 nil 管道会永久阻塞
  2. 关闭的管道读数据仍然可以读数据
  3. 往关闭的管道写数据会 panic
  4. 关闭为 nil 的管道会 panic
  5. 关闭已经关闭的管道 panic

总结:对于一个已初始化,但并未关闭的通道来说,收发操作一定不会引发 panic。但是通道一旦关闭,再对它进行发送操作,就会引发 panic。如果我们试图关闭一个已经关闭了的通道,也会引发 panic。

使用场景: 消息传递、消息过滤,信号广播,事件订阅与广播,请求、响应转发,任务分发,结果汇总,并发控制,限流,同步与异步

-------------本文结束感谢您的阅读-------------
打赏一瓶矿泉水