• go channel 原理


    大家或多或少的接触过了channel 了,我今天想学一下channel的数据结构。

    我有的时候喜欢从一个对象提供的公共接口/功能来猜测这个对象的数据结构,那么今天我们来猜一猜channel。

    1,channel可以存储数据,而且是先进先出,所以我猜测其中包含一个数组或者链表之类的用来保存数据。

    2,channel可以多线程的读写,所以应该还有一个锁,来支持并发。

    3,然后应该还会有一些 长度的属性。

    4,close 一个closed的channel 会panic,所以有一个状态字段保存是否closed,比较科学。

    5,保存数据的数组或者的链表应该是定长的,最起码应该有一个最大长度,不然的话,就可以一直无限写入channel,

    大致的猜测结果有了,那我们来看一下channel是怎么定义的?

    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.
        //
        // Do not change another G's status while holding this lock
        // (in particular, do not ready a G), as this can deadlock
        // with stack shrinking.
        lock mutex
    }

    可以看到,猜到的部分,基本正确。那我们现在来仔细说说这个结构。

     首先,我们定义一个channel

    ch := make(chan int, 2)
    当使用
    <-ch
    ch<- 的时候,就会使用mutex锁住这个ch。然后把数据从goruntine copy到 ch/把数据从ch copy到goruntine,最后释放锁。
    这样就可以实现通过交流来共享内存。Do not communicate by sharing memory;instead,share memory by communicating。

    当ch满了之后,继续使用ch<-,当前goruntine 会阻塞,

    当ch空了之后,继续使用<-ch,当前goruntine 也会阻塞。

    但是,当前goruntine被阻塞之后,什么时候会被唤醒呢?
    但send 阻塞时,goruntine和send的值会被封装成sudog,放到sendq中等待,
    当rev之后,这时候ch不在是满的,sendq 等待列表中的一个数据sudog取出来放到ch中,然后阻塞的goruntine被唤醒
    type waitq struct {
    first *sudog
    last *sudog
    }


    当ch为中的时候,继续send,也会阻塞,但是接着rev操作和上面略有不同
    rev并不锁住ch,而是直接将数据copy给sendq列表中的一个,这样减少了部分锁,增加了效率,确实巧妙
    
    
  • 相关阅读:
    码农自白:这样成为谷歌工程师
    Vim命令合集
    应该知道的Linux技巧
    在Ubuntu上建立Arm Linux 开发环境
    Linux 下socket通信终极指南(附TCP、UDP完整代码)
    Socket通信原理和实践
    用 gdb 调试 GCC 程序
    Quartz学习记录
    shiro学习记录(三)
    shiro学习记录(二)
  • 原文地址:https://www.cnblogs.com/13579net/p/11077244.html
Copyright © 2020-2023  润新知