【Golang 面试题】每日 3 题(二十二)

✍个人博客:Pandaconda-CSDN博客

📣专栏地址:http://t.csdnimg.cn/UWz06

📚专栏简介:在这个专栏中,我将会分享 Golang 面试中常见的面试题给大家~

❤️如果有收获的话,欢迎点赞👍收藏📁,您的支持就是我创作的最大动力💪

64. Go channel 的概念和使用场景

概念:

Go 中的 channel 是一个队列,遵循先进先出的原则,负责协程之间的通信(Go 语言提倡不要通过共享内存来通信,而要通过通信来实现内存共享,CSP (Communicating Sequential Process) 并发模型,就是通过 goroutine 和 channel 来实现的)

使用场景:

  • 停止信号监听
  • 定时任务
  • 生产方和消费方解耦
  • 控制并发数

65. Go channel 的底层数据结构

通过 var 声明或者 make 函数创建的 channel 变量是一个存储在函数栈帧上的指针,占用 8 个字节,指向堆上的 hchan 结构体。

源码包中 src/runtime/chan.go 定义了 hchan 的数据结构:

hchan 结构体:

go 复制代码
type hchan struct {
 closed   uint32   // channel是否关闭的标志
 elemtype *_type   // channel中的元素类型
 // channel分为无缓冲和有缓冲两种。
 // 对于有缓冲的channel存储数据,使用了 ring buffer(环形缓冲区) 来缓存写入的数据,本质是循环数组
 // 为啥是循环数组?普通数组不行吗,普通数组容量固定更适合指定的空间,弹出元素时,普通数组需要全部都前移
 // 当下标超过数组容量后会回到第一个位置,所以需要有两个字段记录当前读和写的下标位置
 buf      unsafe.Pointer // 指向底层循环数组的指针(环形缓冲区)
 qcount   uint           // 循环数组中的元素数量
 dataqsiz uint           // 循环数组的长度
 elemsize uint16                 // 元素的大小
 sendx    uint           // 下一次写下标的位置
 recvx    uint           // 下一次读下标的位置

 // 尝试读取channel或向channel写入数据而被阻塞的goroutine
 recvq    waitq  // 读等待队列
 sendq    waitq  // 写等待队列
 lock mutex //互斥锁,保证读写channel时不存在并发竞争问题
}

等待队列:

双向链表,包含一个头结点和一个尾结点。

每个节点是一个 sudog 结构体变量,记录哪个协程在等待,等待的是哪个 channel,等待发送/接收的数据在哪里。

go 复制代码
type waitq struct {
   first *sudog
   last  *sudog
}
type sudog struct {
    g *g
    next *sudog
    prev *sudog
    elem unsafe.Pointer
    c        *hchan
    ...
}

66. 如何创建 Go channel?

使用 make(chan T, cap) 来创建 channel,make 语法会在编译时,转换为 makechan64 和 makechan。

go 复制代码
func makechan64(t *chantype, size int64) *hchan {
    if int64(int(size)) != size {
        panic(plainError("makechan: size out of range"))
    }
    return makechan(t, int(size))
}

创建 channel 有两种,一种是带缓冲的 channel,一种是不带缓冲的 channel。

go 复制代码
// 带缓冲
ch := make(chan int, 3)
// 不带缓冲
ch := make(chan int)

创建时会做一些检查:

  • 元素大小不能超过 64K。
  • 元素的对齐大小不能超过 maxAlign 也就是 8 字节。
  • 计算出来的内存是否超过限制。

创建时的策略:

  • 如果是无缓冲的 channel,会直接给 hchan 分配内存。
  • 如果是有缓冲的 channel,并且元素不包含指针,那么会为 hchan 和底层数组分配一段连续的地址。
  • 如果是有缓冲的 channel,并且元素包含指针,那么会为 hchan 和底层数组分别分配地址。
相关推荐
茉莉玫瑰花茶24 分钟前
GO [ 方法 ]
开发语言·后端·golang
Wx-bishekaifayuan26 分钟前
django个性化旅游路线推荐平台49005-计算机课程设计、毕业设计
spring boot·后端·python·django·课程设计·express·旅游
Eric_见嘉1 小时前
在职前端 Skill 和 MCP 分享
前端·后端·agent
狗凯之家源码网1 小时前
微博图床 PHP 系统搭建与实战应用指南
android·开发语言·php
an12321212 小时前
ARM嵌入式学习笔记:SPI通信协议详解
arm开发·笔记·学习
孟健2 小时前
出海开发者资金合规:从港卡结汇到完税申报实操
后端·架构
乌暮2 小时前
深入理解 Java 泛型:把「万能盒子」用对、用稳
java·开发语言·后端·学习
Interview Aid1123 小时前
Google SWE Intern Interview Process:OA、Coding 与面试流程详解
面试·职场和发展
架构技术专栏3 小时前
Skill 有效性与稳定性评估:用对照、重复与证据判断价值
后端
2601_962218613 小时前
C语言中三种库的编译和使用方法
开发语言·c++