Golang Channel源码解析源码解析
文章目录文章目录channelsHow to use ChannelsChannel源码解析代码入口channel的结构体新建channelchannel发送元素channel读
取元素关闭channelselect channelchannel reveive valuechannel send value用于判断channel是否关闭的场景
channels
channel存在以下四个特性
goroutine-safe
store and pass values between goroutines
provide FIFO semantics
can cause goroutines to block and unblock
How to use Channels
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan int, 3)
go func() {
for i := 0; i < 10; i++ {
ch <- i
time.Sleep(500 * time.Millisecond)
}
close(ch)
}()
value := <-ch
fmt.Println(value)
for value := range ch {
fmt.Println(value)
}
}
Channel源码解析源码解析
基于的go版本为1.13,源代码位于runtime/chan.go
代码入口代码入口
go的编译器对channel进行处理,从汇编中可以看到具体调用的函数。下面截取了部分的关键代码。
$ go tool compile -S channel.go > channel.s
$ vim channel.s
0x0035 00053 (channel.go:9) CALL runtime.makechan(SB)
0x003e 00062 (channel.go:12) CALL runtime.chansend1(SB)
0x0078 00120 (channel.go:18) CALL runtime.chanrecv1(SB)
0x0067 00103 (channel.go:15) CALL runtime.closechan(SB)
从上面可以看出
当调用make(chan int,4)时,调用的是runtime下的makechan函数
当调用ch <- i时,调用的是runtime下的chansend1函数
当调用value := <-ch时,调用的是runtime下的chanrecv函数
channel的结构体的结构体
type hchan struct {
qcount uint // channel的队列中数据的总数,会随着 变化
dataqsiz uint // channel循环数组的长度,
buf unsafe.Pointer // 指向底层循环数组的指针,只针对缓冲channel
elemsize uint16 //元素大小
closed uint32 //channel是否被关闭的标志
elemtype *_type // 元素类型
sendx uint // 发送元素在循环数组中的索引
recvx uint // 接收元素在循环数组中的索引
recvq waitq // 等待接收的goroutine队列
sendq waitq // 等待发送的goroutine队列