channel和select

channel

Channel是基于有锁队列实现数据在不同协程之间传输的通道,本质上是由buf循环队列、sendq待发送者队列、recvq待接收者队列三个FIFO队列组成的用于协程之间传输数据的协程安全的通道,sendq和recvq可以认为不限大小。

使用

声明一个通道类型的变量是需要使用make()函数初始化

var ch chan int
ch = make(chan int)    // 无缓冲通道
ch = make(chan int, 0) // 无缓冲通道
ch = make(chan int, 3) // 容量为3有缓冲通道

无缓冲通道也被称为同步通道,使用无缓冲通道进行通信的 goroutine 会同步发送和接收。
有缓冲通道当通道内元素数达到最大容量后,向通道执行发送操作就会阻塞。

通道一共有 发送、接收、关闭三种操作

// 发送
ch <- 10   // 将10发送到ch种

// 接收
value := <- ch      // 从ch种接收值并赋值给x变量
value, ok := <- ch  // ok:通道ch关闭时返回false,没有关闭返回true
<- ch               // 从ch中接收值,忽略结果

// 关闭
close(ch)

数据结构

type hchan struct {
	qcount   uint           // total data in the queue
	dataqsiz uint           // size of the circular queue
	buf      unsafe.Pointer // points to an array of dataqsiz elements
	elemsize uint16
	closed   uint32
	elemtype *_type // element type
	sendx    uint   // send index
	recvx    uint   // receive index
	recvq    waitq  // list of recv waiters
	sendq    waitq  // list of send waiters

	// lock protects all fields in hchan, as well as several
	// fields in sudogs blocked on this channel.
	lock mutex
}

type waitq struct {
	first *sudog
	last  *sudog
}

type sudog struct {
	g *g

	next *sudog
	prev *sudog
	...
}

sendq和recvq存储了当前Channel由于缓冲区空间不足而阻塞的Goroutine列表,waitq是一个双向链表,sudog为等待队列中的一个goroutine。

深入分析Go1.18 Channel底层原理

select

select是Go在语言层面提供的多路IO复用的机制,用来检测多个channel是否准备完毕:可读或可写。

select {
case <-ch1:
    // ...
case x := <-ch2:
    // ...use x...
case ch3 <- y:
    // ...
default:
    // ...
}

select的执行有以下情况:

  1. 没有case,deadlock
  2. 满足一个case,执行case,否则执行default
  3. 所有case均无法执行且无default,阻塞
  4. 满足多个case,随机执行一个case

selectgo函数的执行分为四个步骤:首先,随机生成一个遍历case的轮询顺序 pollorder 并根据 channel 地址生成加锁顺序 lockorder,随机顺序能够避免channel饥饿,保证公平性,加锁顺序能够避免死锁;然后,根据 pollorder 的顺序查找 scases 是否有可以立即收发的channel,如果有则获取case索引进行处理;再次,如果pollorder顺序上没有可以直接处理的case,则将当前 goroutine 加入各 case 的 channel 对应的收发队列上并等待其他 goroutine 的唤醒;最后,当调度器唤醒当前 goroutine 时,会再次按照 lockorder 遍历所有的case,从中查找需要被处理的case索引进行读写处理,同时从所有case的发送接收队列中移除掉当前goroutine

深入分析Go1.18 select底层原理

posted @ 2024-01-23 20:46  及第  阅读(11)  评论(0编辑  收藏  举报