• 关于Go语言的底层,Channel


    1.Channel

    介绍一下Channel(有缓冲和无缓冲)
    Go 语言中,不要通过共享内存来通信,而要通过通信来实现内存共享。Go 的CSP(Communicating Sequential Process)并发模型,中文可以叫做通信顺序进程,是通过 goroutine 和 channel 来实现的。
    所以 channel 收发遵循先进先出 FIFO,分为有缓存和无缓存,channel 中大致有 buffer(当缓冲区大小部位 0 时,是个 ring buffer)、sendx 和 recvx 收发的位置(ring buffer 记录实现)、sendq、recvq 当前 channel 因为缓冲区不足 而阻塞的队列、使用双向链表存储、还有一个 mutex 锁控制并发、其他原属等。

    // 无缓冲的channel由于没有缓冲发送和接收需要同步
    ch := make(chan int)   
    //有缓冲channel不要求发送和接收操作同步
    ch := make(chan int, 2)  
    
    • 1
    • 2
    • 3
    • 4

    channel 无缓冲时,发送阻塞直到数据被接收,接收阻塞直到读到数据;channel有缓冲时,当缓冲满时发送阻塞,当缓冲空时接收阻塞。

    2.Channel实现原理

    • channel 内部维护了两个 goroutine 队列,一个是待发送数据的 goroutine 队列,另一个是待读取数据的
      goroutine 队列。
    • 每当对 channel 的读写操作超过了可缓冲的 goroutine 数量,那么当前的 goroutine
      就会被挂到对应的队列上,直到有其他 goroutine 执行了与之相反的读写操作,将它重新唤起。

    3.Channel读写流程

    向 channel 写数据:
    若等待接收队列 recvq 不为空,则缓冲区中无数据或无缓冲区,将直接从 recvq 取出 G ,并把数据写入,最后把该 G 唤醒,结束发送过程。
    若缓冲区中有空余位置,则将数据写入缓冲区,结束发送过程。
    若缓冲区中没有空余位置,则将发送数据写入 G,将当前 G 加入 sendq ,进入睡眠,等待被读 goroutine 唤醒。
    从 channel 读数据
    若等待发送队列 sendq 不为空,且没有缓冲区,直接从 sendq 中取出 G ,把 G 中数据读出,最后把 G 唤醒,结束读取过程。
    如果等待发送队列 sendq 不为空,说明缓冲区已满,从缓冲区中首部读出数据,把 G 中数据写入缓冲区尾部,把 G 唤醒,结束读取过程。
    如果缓冲区中有数据,则从缓冲区取出数据,结束读取过程。
    将当前 goroutine 加入 recvq ,进入睡眠,等待被写 goroutine 唤醒。

    关闭 channel

    1.关闭 channel 时会将 recvq 中的 G 全部唤醒,本该写入 G 的数据位置为 nil。将 sendq 中的 G 全部唤醒,但是这些 G 会 panic。
    panic 出现的场景还有:

    • 关闭值为 nil 的 channel
    • 关闭已经关闭的 channel
    • 向已经关闭的 channel 中写数据

    Channel为什么能做到线程安全

    Channel 可以理解是一个先进先出的队列,通过管道进行通信,发送一个数据到Channel和从Channel接收一个数据都是原子性的。不要通过共享内存来通信,而是通过通信来共享内存,前者就是传统的加锁,后者就是Channel。设计Channel的主要目的就是在多任务间传递数据的,本身就是安全的。

    Channel是同步进行还是异步的(Channel的三种状态)
    Channel是异步进行的, channel存在3种状态:

    nil,未初始化的状态,只进行了声明,或者手动赋值为nil
    active,正常的channel,可读或者可写
    closed,已关闭,千万不要误认为关闭channel后,channel的值是nil

    在这里插入图片描述
    给一个 nil channel 发送数据,造成永远阻塞
    从一个 nil channel 接收数据,造成永远阻塞
    给一个已经关闭的 channel 发送数据,引起 panic
    从一个已经关闭的 channel 接收数据,如果缓冲区中为空,则返回一个零值
    无缓冲的 channel 是同步的,而有缓冲的 channel 是非同步的
    关闭一个 nil channel 将会发生 panic
    在这里插入图片描述

  • 相关阅读:
    深入理解 pytest Fixture 方法及其应用!
    conn,cur=DBHelper.connDB(DBconfig.A)是什么意思
    Unity的BuildPlayerProcessor:深入解析与实用案例
    NVR新版界面看回放时音频功能如何开启
    web期末大作业:基于html+css+js制作 学校班级网页制作----校园运动会 4页
    BFT问题思考
    TS中的枚举是什么如何使用
    深入理解Java中的线程安全List:CopyOnWriteArrayList原理和应用
    代码仓库操作
    数据安全前沿技术研究小结
  • 原文地址:https://blog.csdn.net/m0_73728511/article/details/133621710