美文网首页我爱编程
Go小技巧(一)— 获取channel属性

Go小技巧(一)— 获取channel属性

作者: sipt | 来源:发表于2018-06-20 14:52 被阅读141次

    概述

    这里一个介绍一个方法,可以在不取channel里的数据的前提下,查看channel是否关闭,是否阻塞,缓冲大小,通道内当前缓冲数据量等。
    在这里需要了解一下golang的内存模型,然后通过指针取出相应的值。

    channel的结构体在chan.go中:

    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
        //... 以下字段没有用上,先省略
    }
    

    从上面可以看出,现在要从出取出:

    • qcount:queue里的数据总数
    • dataqsiz:queue的最大长度
    • closed:是否关闭

    实现

    首先我们定义一个struct来与hchan对应。(因为hchan里的字段长度不定,qcountdataqsiz都是uint还好说,主要是取closed中间隔了个unint16,所以这里偷个懒)

    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
    }
    

    省略字段这里没用到,所以直接去掉就行了,上面的属性顺序和类型要与原hchan必须保持一致。
    这里想把它通用化所以包成方法接收的会是个interface{},如里channel给interface{}那它在golang底层会被解析成eface

    type eface struct {
        _type *_type
        data  unsafe.Pointer
    }
    

    所以先将指针定位到eface.data再将指向的数据空间转为自定义的hchan

    i := (*[2]uintptr)(unsafe.Pointer(&c))
    h := (*hchan)(unsafe.Pointer(i[1]))
    

    这时h中值已经注入了。

    附录

    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
    }
    type ChanInfo struct {
        Closed bool  // 是否关闭
        Len    uint  // channel内数据量
        Cap    uint  // channel容量
        Block  bool  // 是否已经阻塞
    } 
    
    func ChanStatus(c interface{}) (*ChanInfo, error) {
        v := reflect.ValueOf(c)
        if v.Type().Kind() != reflect.Chan {
            return nil, errors.New("type must be channel")
        }
        i := (*[2]uintptr)(unsafe.Pointer(&c))
        h := (*hchan)(unsafe.Pointer(i[1]))
        return &ChanInfo{
            Cap:    h.dataqsiz,
            Len:    h.qcount,
            Closed: h.closed == 1,
            Block:  h.qcount >= h.dataqsiz,
        }, nil
    }
    

    相关文章

      网友评论

        本文标题:Go小技巧(一)— 获取channel属性

        本文链接:https://www.haomeiwen.com/subject/stkxyftx.html