Go channel

2023-09-25 ⏳0.9分钟(0.4千字)

设计原理

Go 语言中最常见的、也是经常被人提及的设计模式就是:不要通过共享内存的方式进行通信,而是应该通过通信的方式共享内存。在很多主流的编程语言中,多个线程传递数据的方式一般都是共享内存,为了解决线程竞争,我们需要限制同一时间能够读写这些变量的线程数量,然而这与 Go 语言鼓励的设计并不相同。

type hchan struct {
	qcount   uint
	dataqsiz uint
	buf      unsafe.Pointer
	elemsize uint16
	closed   uint32
	elemtype *_type
	sendx    uint
	recvx    uint
	recvq    waitq
	sendq    waitq

	lock mutex
}

type waitq struct {
	first *sudog
	last  *sudog
}

发送数据 ch <- i

在发送数据的逻辑执行之前会先为当前 Channel 加锁,防止多个线程并发修改数据。如果 Channel 已经关闭,那么向该 Channel 发送数据时会报 “send on closed channel” 错误并中止程序。

接收数据 i <- ch

如果当前 Channel 已经被关闭并且缓冲区中不存在任何数据,那么会清除ep指针中的数据并立刻返回。

关闭管道

Channel是一个空指针或者已经被关闭时,Go语言运行时都会直接崩溃并抛出异常;

recvqsendq两个队列中的数据加入到 Goroutine 列表gList中,与此同时该函数会清除所有runtime.sudog`上未被处理的元素.

该函数在最后会为所有被阻塞的 Goroutine 调用runtime.goready触发调度。