golang chan解读--物流中心开张了
这几天在学习golang chan的使用,为了方便理解,可以把chan当成是物流中心,goroutine是一些好吃懒做的人,没事就喜欢睡觉,为了解决这些人的睡觉问题,chan的老板盖了两栋宿舍楼,一栋叫recvq给收快递的人用,一栋叫sendq给发快递的人,为了防止这些人赖着不走,规定宿舍楼只对那些等着发快递和等着收快递的人开放。发快递的流程是这样的,goroutine拿着快递来到快递中心,快递中心会去recvq看看有没有收快递的人,如果有就叫醒一个goroutine来拿走快递然后把他赶走。如果没有,就安排发快递的人去sendq宿舍睡觉。收快递则反过来,goroutine过来找老板看看有没有快递,老板就去sendq宿舍看看有没有人,有就叫醒一个,把快递给他并把他赶出宿舍。如果sendq宿舍没人,就安排收快递的人去recvq宿舍睡觉。这样一个物流中心就这么运作起来了。
随着业务的发展,老板发现几个问题,如果来发快递的人远远超过收快递的人或者反过来,宿舍就不够用了,所以老板脑门一拍,整个buf仓库吧,这样如果快递发不出去就送到仓库,缓解一下宿舍的压力。此时发快递的流程没变,只是在没有人收的情况下,把快递放到仓库,发送人可以直接回去,如果仓库满了还是安排发快递的到sendq宿舍睡觉。收快递的时候变成这样,老板先看看仓库有没有快递,有的话直接让人拿走,然后去sendq宿舍叫醒一个人,让他把快递放仓库然后赶走。如果仓库没有快递呢,就还是原来的流程。
解决了上面几个问题之后,老板生意越做越大,结果膨胀了,连开了好几家chan模式的物流中心。结果有一些物流中心出现了亏损,于是老板决定关掉一些物流中心,为了尽量避免客户投诉,采取了一些措施,首先弄了一个closed的牌子,告诉大家物流中心已经关掉了,防止产生新的业务。然后老板会叫醒宿舍所有的人,把他们统统解散,并且拆掉宿舍,如果仓库里还有快递,则保留仓库,并对所有人开放。
以上就是我个人对chan数据结构的一些生活化的描述,便于自己理解和掌握,如果有什么错误之处,欢迎指正。
实验代码
func main() {
c := make(chan string, 3)
c <- "快递1"
c <- "快递2"
go func() {
a, ok := <-c
fmt.Println(a, ok)
fmt.Println("bye bye")
}()
time.Sleep(1000)
close(c)
b, ok := <-c
fmt.Println(b, ok)
time.Sleep(1000)
}
chan数据结构
type hchan struct {
qcount uint // queue 里面有效用户元素,这个字段是在元素出对,入队改变的;
dataqsiz uint // 初始化的时候赋值,之后不再改变,指明数组 buffer 的大小;
buf unsafe.Pointer // 指明 buffer 数组的地址,初始化赋值,之后不会再改变;
elemsize uint16 // 指明元素的大小,和 dataqsiz 配合使用就能知道 buffer 内存块的大小了;
closed uint32
elemtype *_type // 元素类型,初始化赋值;
sendx uint // send index
recvx uint // receive index
recvq waitq // 等待 recv 响应的对象列表,抽象成 waiters
sendq waitq // 等待 sedn 响应的对象列表,抽象成 waiters
// 互斥资源的保护锁,官方特意说明,在持有本互斥锁的时候,绝对不要修改 Goroutine 的状态,不能很有可能在栈扩缩容的时候,出现死锁
lock mutex
}