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

sipt · · 3550 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

概述

这里一个介绍一个方法,可以在不取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
}

有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:sipt

查看原文:Go小技巧(一)— 获取channel属性

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

3550 次点击  
加入收藏 微博
1 回复  |  直到 2020-09-03 18:25:40
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传