带缓冲的chan是最简消息队列的核心,因其天然具备fifo、goroutine安全与暂存能力;无缓冲chan仅同步点,无法积压消息;缓冲大小需权衡背压与内存,推荐从16或64起步,避免过大导致oom或掩盖性能瓶颈。

纯用 chan 实现的消息队列,适合理解原理,但不能替代真实 MQ;它不持久、无重试、无 ACK,只在内存中流转,关掉程序消息就丢。
为什么带缓冲的 chan 是最简消息队列的核心
Go 的 chan 本身是线程安全的 FIFO 队列,加缓冲后就能解耦生产与消费速度差。不带缓冲的 chan 是同步阻塞,一发一收;带缓冲的(如 make(chan string, 10))才具备“暂存”能力,这才是队列感的来源。
- 缓冲大小不是越大越好:设为
1000可能掩盖背压问题,OOM 风险上升;建议从16或64起步,按压测结果调 - 写入时若缓冲满,默认会阻塞;想非阻塞,必须用
select+default分支 -
len(ch)返回当前已缓存数量,cap(ch)返回容量,两者都可 runtime 观察,但别用来做业务逻辑判断(竞态下可能过期)
close(ch) 的真实语义和常见误用
close(ch) 不是“清空 channel”,而是发送一个“关闭信号”,仅影响接收端:value, ok := 中的 <code>ok 变为 false,且后续读到零值。它只应在**所有生产者都结束写入后**由最后一个生产者调用。
Colly 是一个用于 Go 语言的快速开源爬取和爬虫框架。它适用于从简单的页面提取到异步爬虫处理大量页面集合,支持请求回调和结构化解析。
- 多个生产者共用一个
chan时,不能各自close,否则 panic:“close of closed channel” - 消费者用
for range ch是安全的,它自动检测close并退出;但若混用和 <code>range,行为不可控 - 关闭后仍向
ch写入会 panic;可用recover捕获,但更应从设计上避免——比如用sync.WaitGroup确保所有生产者退出后再 close
如何让单个 chan 支持多消费者并控制并发数
直接把同一个 chan 传给多个 goroutine 消费,Go 运行时会自动负载分发(FIFO 保证,但无严格轮询)。但若需硬限流(如限制最多 5 个并发处理),不能只靠 chan 缓冲区,得额外加控制层。
- 用
semaphore模式:定义sem := make(chan struct{}, 5),每个消费者处理前先sem ,处理完再 <code> - 不要试图用
len(ch)做限流依据——它只反映缓冲区剩余空间,不反映正在处理中的消息数 - 若消费者需要反馈(如通知生产者“这条已处理完”),得单独开一个
done chan int或在消息结构体里嵌入DoneChan chan
什么时候该放弃 chan,转向真实 MQ
当出现以下任一情况,说明你已经踩出玩具边界:需要消息持久化、跨进程/跨机器通信、死信队列、延时消息、精确一次投递、或要求高可用——这些 chan 根本不提供。
此时该切到 amqp(RabbitMQ)、github.com/segmentio/kafka-go 或云厂商的托管服务。本地开发调试阶段用 chan 没问题,但上线前必须评估 SLA;很多人卡在“功能跑通了就以为能上生产”,其实只是没遇到消息积压、网络分区或进程崩溃这些真实故障。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










