A channel holding the empty struct make(chan struct{}) is a clear message to the user that no information is transmitted over the channel and that's purely used for synchronization.

Regarding unbuffered channels, a channel write will block until a corresponding read occurs from another goroutine. The same is true for a channel reading blocking while waiting for a writer.

生产者-消费者模型

**带缓冲:**缓冲放满阻塞生产者,缓冲清空阻塞消费者

不带缓冲:缺任何一方都会阻塞另一方

单纯地将函数并发执行没有意义,函数与函数间需要交换数据才能体现并发执行函数的意义。虽然可以使用共享内存进行数据交换,但是共享内存在不同的 goroutine 中容易发生竞态问题。为了保证数据交换的正确性,必须使用互斥量对内存进行加锁,这种做法势必造成性能问题。

Go 提倡使用通信的方法代替共享内存

在公共场所人很多的情况下,大家养成了排队的习惯,目的也是避免拥挤、插队导致的低效的资源使用和交换过程,代码与数据也是如此。多个 goroutine 为了争抢数据,势必造成执行的低效率,使用队列的方式是最高效的,channel 就是一种队列一样的结构。

在任何时候,同时只能有一个 goroutine 访问通道进行发送和获取数据。goroutine 间通过通道就可以通信。channel 像一个传送带或队列,遵循先入先出 FIFO 保证收发数据的顺序

By default, sends and receives block until the other side is ready. This allows goroutines to synchronize without explicit locks or condition variables. The example code sums the numbers in a slice, distributing the work between two goroutines. Once both goroutines have completed their computation, it calculates the final result.

Implementation 实现

type hchan struct {
	buf      unsafe.Pointer // 缓冲区数据指针
	sendx    uint // 发送操作处理到的位置
	recvx    uint // 接收操作处理到的位置
	
	recvq    waitq
	sendq    waitq

	closed   uint32
	lock mutex
}

sendq和 recvq 存储了当前 Channel 由于缓冲区空间不足而阻塞的 Goroutine 列表,这些等待队列使用双向链表 runtime.waitq 表示,链表中所有的元素都是 runtime.sudog 结构:

type waitq struct {
	first *sudog
	last *sudog
}

runtime.sudog表示一个在等待列表中的 Goroutine,该结构中存储了两个分别指向前后 runtime.sudog的指针以构成链表。

Untitled