zoukankan      html  css  js  c++  java
  • Channel底层原理

    hchan结构体

    通道在运行时是一个特殊的hchan结构体,结构体内容如下:

    • qcount 通道队列中数据个数
    • dataqsiz 通道队列中的数据大小
    • buf 存放实际数据的指针
    • elemsize 通道类型大小
    • closed 通道是否关闭
    • elemtype 通道类型
    • sendx 记录发送者在buf中的序号
    • recvx 记录接受者在buf中的序号
    • recvq 读取的阻塞协程队列
    • sendq 写入的阻塞协程队列
    • lock 锁,并发保护

    线性数组模拟环形队列

    有缓存通道存储在buf中的数据虽然是线性的数组,但是用数组和序号revcx和recvq模拟了一个环形队列,recvx可以找到buf哪个位置获取通道中的元素,而sendx能够找到写入时放入buf的位置,这样做主要是为了重用已经使用过的空间。recvx到sendx的距离代表通道队列中元素的数量。

    当到达循环队列末尾时,sendx会置为0,以防止下一次写入0号位置,开始循环利用空间。这样同样意味着通道中只能放入指定大小的数据,当通道中的数据满了以后,再次写入数据将陷入等待,直到第0号位置被取出后,才能继续写入。

    通道初始化

    通道初始化在运行时调用了makechan函数,第1个参数代表通道的类型,第2个参数通道中元素的大小。makechan会判断元素的大小,对齐等。最重要的是它会在内存中分配元素大小。

    当分配大小为0是,只要在内存中分配hchan结构体的大小即可

    当通道的元素中不包含指针时,连续分配hchan结构体大小+size元素大小

    当通道元素中包含指针时,需要单独分配内存空间,因为当通道元素中包含指针时,需要单独分配空间才能正常进行垃圾

    通道写入

    运行时调度用chansend方法,分为3中不同情况:

    1. 有正在等待的读取协程

      当有读取的协程正在等待时,直接从等待的读取协程链表中获取第一个协程,并将元素直接复制到对应的协程中,再唤醒被堵塞的协程。

    2. 缓冲区有空余

      如果队列中没有正在等待的协程,但是通道是带缓冲区的,并且当前缓冲区没有满,则向当前缓冲区写入元素。

    3. 缓冲区无空余

      当前通道无缓冲区或者当前缓冲区已经满了,则代表当期那协程的sudog结构需要放入sendq链表末尾,并且当前协程陷入休眠状态,等待被唤醒重新执行。

    通道读取

    读取与写入原理相似,在运行时调用chanrecv函数

    1. 有正在等待的写入协程

      从等待协程的写入协程链表中获取第一个协程,并将写入的元素直接复制到当前协程中,再唤醒被堵塞的写入协程。

    2. 缓冲区有元素

      读取缓冲区中的数据,并写如当前的读协程中。

    3. 缓冲区无元素

      无缓冲区或者当前缓冲区已经空了,代表当前协程的sudog结构需要放入recvq链表末尾,并将当前协程陷入休眠状态,等待被唤醒重新执行。

  • 相关阅读:
    三级菜单的实现方式
    简单登录接口实践
    C++中的set和java的hashset有何区别?
    css 利用文档结构给列表添加样式
    谈谈我对JS中this的理解
    谈谈我对JS原型的理解
    使用node.js,实现简单的JS文件合并小工具
    谈谈我对JS闭包的理解
    谈谈我对JS作用域的理解
    模拟实现 百度翻译 右下方的可折叠的分享按钮列表
  • 原文地址:https://www.cnblogs.com/hzpeng/p/15415299.html
Copyright © 2011-2022 走看看