卡码笔记-最强八股文
首页
计算机基础
C++
Java
Go
🔥大模型🔥
  • 大模型面经
  • Java面经
  • C++面经
简历专栏
代码随想录 (opens new window)
首页
计算机基础
C++
Java
Go
🔥大模型🔥
  • 大模型面经
  • Java面经
  • C++面经
简历专栏
代码随想录 (opens new window)
  • 本栏必读

    • Go语言面试题专栏介绍
  • 语言基础

  • 内存管理

  • 并发编程

    • 什么是Goroutine
    • 协程、线程、进程的区别
    • 协程如何通信
    • 怎么实现协程池
    • Goroutine创建数量有限制吗
    • Goroutine阻塞场景与调度器行为
    • 等待多个goroutine执行结果
    • 无缓冲和有缓冲channel区别
      • 简要回答
      • 详细回答
      • 知识图解
      • 知识扩展
    • 关闭channel的行为与安全关闭
    • nil channel读取会发生什么
    • channel死锁场景与避免策略
    • select语句的执行机制
    • sync.Mutex正常模式与饥饿模式
    • sync.Mutex底层锁状态实现
    • sync.Map并发安全与优缺点
    • context实现超时取消控制
    • Context.Value使用场景与注意事项
  • 底层原理

# Go语言中无缓冲和有缓冲的channel有什么区别?

无缓冲和有缓冲的channel有什么区别?

# 简要回答

无缓冲 channel 是同步的,发送和接收操作会相互阻塞,直到双方都准备好(即“手递手”交付)。

有缓冲 channel 在缓冲区未满或未空时是异步的,发送操作只有在缓冲区满时才会阻塞,接收操作只有在缓冲区空时才会阻塞。

无缓冲 channel 保证了强同步性,而有缓冲 channel 实现了发送和接收操作在时间上的解耦。

# 详细回答

无缓冲 channel 和有缓冲 channel 的核心区别在于同步性和内部存储结构。

  • 无缓冲 channel:其容量(capacity)为 0。发送者会阻塞直到接收者就绪,接收者也会阻塞直到发送者就绪。这种机制确保了数据交换的原子性和即时性。
  • 有缓冲 channel:拥有一个固定大小的缓冲区。发送者只需将数据放入缓冲区即可返回,除非缓冲区已满;同理,接收者只需从缓冲区取出数据,除非缓冲区为空。这允许生产者和消费者以不同的速率运行。
  • 实现机制:无缓冲 channel 在双方都准备好时,数据往往直接从发送者的栈拷贝到接收者的栈变量中,不经过缓冲区;有缓冲 channel 则必须经过环形缓冲区的拷贝。
  • 应用场景:无缓冲 channel 适用于需要强同步、即时确认的场景;有缓冲 channel 适用于生产者-消费者模型,用于平滑突发流量或提高吞吐量。

# 知识图解

image

# 知识扩展

在 Go 运行时,channel 由 hchan 结构体表示。底层工作原理如下:

  1. 环形缓冲区:
    • buf 指向一个数组,dataqsiz 是其长度。
    • sendx 和 recvx 分别记录发送和接收的索引,利用取模运算实现环形队列,避免数据搬移,提高效率。
  2. 锁:
    • lock 保证了并发安全,所有对 Channel 的操作(发送、接收、关闭)都需要持有这把锁。
  3. 等待队列:
    • sendq 和 recvq 是双向链表,存储了因操作该 Channel 而阻塞的 Goroutine(封装为 sudog 结构体)。
    • 当 Channel 缓冲区满时,发送者会被加入 sendq 并挂起;当缓冲区空时,接收者会被加入 recvq 并挂起。
    • 当有数据被接收或发送时,会从对应的等待队列中唤醒一个 Goroutine 直接传递数据或获取缓冲区数据,减少上下文切换开销。
  4. 类型安全:
    • elemtype 和 elemsize 保证了 Go Channel 是类型安全的,编译器会在编译期检查类型匹配。

# 面试官可能会追问

Q1:如何选择使用无缓冲还是有缓冲 channel?

A1:在选择 channel 类型时,应该考虑数据传递的方式和并发模型。

如果发送和接收需要严格同步,如任务分配,应该使用无缓冲 channel。

如果发送和接收可以在时间上分离,如日志收集,应该使用有缓冲 channel。

Q2:如何优雅地关闭 channel?

A2:关闭 channel 通常是由发送者负责关闭,因为发送者知道何时没有更多的数据要发送。

在关闭 channel 之前,应该确保所有发送操作已经完成。

可以使用 sync.WaitGroup 来等待所有发送 goroutine 完成,然后再关闭 channel。

另外,在接收端应该检查 channel 是否已经关闭,避免接收零值。

Last Updated: 4/29/2026, 3:26:47 PM

← 等待多个goroutine执行结果 关闭channel的行为与安全关闭 →

评论

验证登录状态...

侧边栏
夜间
卡码简历
代码随想录
卡码投递表🔥
2026群
添加客服微信 PS:通过微信后,请发送姓名-学校-年级-2026实习/校招
支持卡码笔记
鼓励/支持/赞赏Carl
1. 如果感觉本站对你很有帮助,也可以请Carl喝杯奶茶,金额大小不重要,心意已经收下
2. 希望大家都能梦想成真,有好的前程,加油💪