千家信息网

Golang中Channel数据结构的作用是什么

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,本篇文章给大家分享的是有关Golang中Channel数据结构的作用是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。channel
千家信息网最后更新 2026年11月03日Golang中Channel数据结构的作用是什么

本篇文章给大家分享的是有关Golang中Channel数据结构的作用是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。


channel 的需求描述

为了理解这些数据结构解决了什么问题,我们先来做个简单的回顾,看看为什么需要这两个数据结构,他们解决了什么问题。我们知道 goroutine 是用户态的线程,不同的 goroutine 之间是有消息传递这个需求的。在原始的进程与线程(系统线程)编程中我们会采用管道的方式,而 channel 就是用户态线程传递消息的管道实现,并且是类型安全的。

既然 channel 是一个管道,用来满足不同 goroutine 间交换消息的。那么实现这样一个管道要怎么做呢?

来看看我们日常传递消息的需求:

  1. 能够有多个 goroutine 向 channel 进行读写,并且保证没有竞争问题,需要用 队列 来管理阻塞的 goroutine,解决竞争问题;
  2. 需要管理发送到 channel 的消息(有缓冲、无缓冲),对于有缓存的 channel 可以采用 循环队列 来管理多个消息。

当然上面的需求是经过简化的,比如 channel 还需要具备阻塞、唤醒 goroutine 的能力,不过为了本文我们更加专注焦点问题,先只关注上面两个问题。

channel 的数据结构

接下来我们分析一下 channel 在实际运行中,它的结构体是怎么样的。当然这又分为两种类型,有缓冲与无缓冲的。我们先来看一个无缓冲的情况。

无缓冲

先把示例代码贴出来。就是两个读的 goroutine 被阻塞在一个无缓冲的 channel 上。

func main() {
ch := make(chan int) // 无缓冲

go goRoutineA(ch)
go goRoutineB(ch)
ch <- 1

time.Sleep(time.Second * 1)
}

func goRoutineA(ch chan int) {
v := <-ch
fmt.Printf("A received data: %d\n", v)
}

func goRoutineB(ch chan int) {
v := <-ch
fmt.Printf("B received data: %d\n", v)
}

来看看当代码执行到 ch <- 1 这一行之后 channel 的结构体被填充成什么样子了!

无缓冲 channel

注意其中 buf 字段可存储的长度是0,这是因为 无缓冲 channel 不会用到循环队列来存储数据。它一定是等读、写 goroutine 都准备好了,然后直接把数据交给对方。我们用一副图来看一下无缓冲的数据交换过程。

交换数据

上图描述的是数据交换过程,再看一下读 goroutine 被阻塞的结构示意图。被阻塞的 goroutine 会挂载到对应的队列上,该队列是一个双端队列。

上面的例子,由于两个读 goroutine 在启动的时候,写还没有准备好,因此读全部被挂起在队列中;当有写goroutine准备好的时候,由于此时读已经就绪,因此写不会阻塞,挂起放到 sendq 中。大家可以修改上面的代码,自己看一下写阻塞,读立马执行的情况。

结构示例

有缓冲

我们将上面的代码改成有缓冲的通道,然后再来看看有缓冲的情况。

func main() {
ch := make(chan int, 3) // 有缓冲

// 都不会阻塞
ch <- 1
ch <- 2
ch <- 3
// 会阻塞,被挂起到 sendq 中
go func() {
ch <- 4
}()

// 只是为了debug
var a int
fmt.Println(a)

go goRoutineA(ch)
go goRoutineA(ch)
go goRoutineB(ch)
go goRoutineB(ch) // 猜猜这里会被挂起吗?

time.Sleep(time.Second * 2)
}

func goRoutineA(ch chan int) {
v := <-ch
fmt.Printf("A received data: %d\n", v)
}

func goRoutineB(ch chan int) {
v := <-ch
fmt.Printf("B received data: %d\n", v)
}

贴出执行到第一行的 go goRoutineA(ch) 时, hchan 的结构填充情况。

有缓冲 channel

在这里可以看到缓冲的大小是3,由于增加了缓冲,只要写 goroutine 没有把缓冲写满,则不会导致协程阻塞。但是一旦缓冲没有多余的空间,则会把写 goroutine 挂起到 sendq 中,直到有空间时将他唤醒(还有其它唤醒的场景,这一略过)。

其实有缓冲的 channel,就是把同步的通信变为了异步的通信。写的 channel 不需要关注读 channel,只要有空间它就写;而读也一样,只要有数据就正常读就可以,如果没有就挂起到队列中,等待被唤醒。下图形象的展示了有缓冲 channel 是如何交换数据的。

交换数据

我们再来用图的形式看一下此时结构体的样子,这里图有些偷懒,只是在上面图的基础上增加了循环队列部分的描述,实际到该例子中,读 goroutine时不会被阻塞的,看的时候需要注意这一点。

结构示例

循环队列

今天最重要的是理解 channel 中两个关键的数据结构。为了下一讲阅读源码做准备,我把 channel 中的循环队列部分的代码抽象出来了。

// 队列满了
var ErrQFull = errors.New("circular is full")

// 没有值
var ErrQEmpty = errors.New("circular is empty")

// 定义循环队列
// 如何确定队空,还是队满?q.sendx = (q.sendx+1) % q.dataqsiz
type queue struct {
buf []int // 队列元素存储
dataqsiz uint // circular 队列长度
qcount uint // 有多少元素在buf中 qcount = len(buf)
sendx uint // 可以理解为队尾指针,向队列写入数据
recvx uint // 可以理解为队头指针,从队列读取数据
}

func makeQ(size int) *queue {
q := &queue{
dataqsiz: uint(size),
buf: nil,
}

q.buf = make([]int, q.dataqsiz)

return q
}

// 向buf中写入数据
// 请看 chansend 函数
func (c *queue) insert(ele int) error {
// 检查队列是否有空间
if c.dataqsiz > 0 && c.qcount == c.dataqsiz {
return ErrQFull
}

// 存入数据
c.buf[c.sendx] = ele
c.sendx++ // 尾指针后移
if c.sendx == c.dataqsiz { // 如果相等,说明队列写满了,sendx放到开始位置
c.sendx = 0
}
c.qcount++

return nil
}

// 从buf中读取数据
func (c *queue) read() (int, error) {
// 队列中没有数据了
if c.dataqsiz > 0 && c.qcount == 0 {
return 0, ErrQEmpty
}

ret := c.buf[c.recvx] // 取出元素
c.buf[c.recvx] = 0
c.recvx++
if c.recvx == c.dataqsiz { // 如果相等,说明写到末尾了,recvx放到开始位置
c.recvx = 0
}
c.qcount--

return ret, nil
}

以上就是Golang中Channel数据结构的作用是什么,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注行业资讯频道。

缓冲 数据 队列 结构 阻塞 数据结构 消息 问题 循环 两个 代码 就是 情况 管道 线程 需求 面的 准备 元素 指针 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 百单网互联网科技有限公司 互联网科技名片 互联网科技公司起名 互联网的科技 涨乐互联网科技 科技互联网公司装修 金融科技还是互联网 中国互联网科技发展 互联网与未来科技 广州善班互联网科技 华脉科技工业互联网产品 富国互联网科技创新基金 中国互联网公司排名锤子科技 企晟互联网信息科技有限公司 西安小鹰速贷互联网科技有限公司 卓翼科技产业互联网合作 每天都有哪些好的互联网科技 科技互联网公司两年变化 盐城市攀科互联网科技有限公司 重庆科技产业互联网有哪些 云创客互联网科技公司 千方科技属于互联网企业吗 未来五年的互联网科技 明优互联网科技有限公司 广州百诚互联网科技有限公司官网 工业互联网科技创业 兰石爱特工业互联网科技分公司 中国互联网公司的科技投入 广西泛欧互联网科技有限公司 互联网对科技影响
0