make(chan int) 和 make(chan int, 1) 行为完全不同:前者是无缓冲通道,发送必阻塞直至接收就绪,实现强同步;后者是有缓冲通道(容量为1),发送在缓冲未满时立即返回,实现异步解耦,本质是控制流语义的根本切换。

Go 的并发不是“加了 goroutine 就能并发”,而是整套调度、通信、生命周期管理的协同结果;CSP 不是口号,是 channel 阻塞规则、goroutine 调度时机、select 多路复用行为的总和。
为什么 make(chan int) 和 make(chan int, 1) 行为完全不同
无缓冲 channel 是同步点:发送方必须等到接收方就绪才能继续;有缓冲 channel 则允许发送方在缓冲未满时立刻返回。这不是“性能差异”,而是控制流语义的根本切换。
- 用
make(chan int)实现 producer-consumer 协调时,天然强制生产与消费节奏对齐 —— 适合需要强顺序保证的场景(如状态机驱动) - 用
make(chan int, 1)后,producer 可能连续发两个值而不阻塞,但第二个值会阻塞直到 consumer 消费第一个 —— 容易误以为“已解耦”,实则只是把背压延迟了一步 - 缓冲大小 ≠ 并发数:设
make(chan int, 100)不代表能安全启动 100 个 goroutine 往里塞数据;若 consumer 崩溃或卡住,buffer 会填满,后续 send 全部挂起,最终导致 goroutine 泄漏
select 里不写 default 就等于主动制造死锁风险
select 本意是解决“等哪个 channel 先就绪”,但它的默认行为是:所有 case 都不可达时,整个 select 阻塞。这在循环中极易演变成静默死锁。
- 常见错误:在 worker goroutine 中写
select { case msg := ,却没加 <code>default:或case —— 若 <code>inchannel 关闭后不再有新消息,且没其他退出路径,goroutine 永久阻塞 - 正确做法不是“加
default就万事大吉”,而是明确退出条件:case msg, ok := ,或配合 <code>context.Context的Done()channel -
select的 case 是**伪随机**执行的(runtime 内部打乱顺序),不能依赖书写顺序判断优先级;想保序必须靠业务逻辑控制,而非 case 排列
goroutine 泄漏往往藏在 range 和 close() 的配合里
for range ch 会一直阻塞等待新值,直到 channel 被关闭;但关闭时机错位,就会让一部分 goroutine 永远等不到 close。
- 典型陷阱:producer 发完数据后
close(ch),但 consumer 已提前退出(比如处理异常后 return),此时range未触发,channel 却被关 —— 后续所有往该 channel 的 send 都 panic - 更隐蔽的是:多个 producer 共用一个 channel,但只由其中一个调用
close()—— Go 不允许重复 close,也不允许未 close 时range结束,结果是部分 goroutine 挂在 recv,部分挂在 send - 安全模式只有两种:单 producer + close,或用
sync.WaitGroup确保所有 producer 完成后再 close;range只应在明确知道 channel 必定被关闭、且仅由一方关闭时使用
所谓“不要共享内存”,是指别让 goroutine 直接读写同一 map 或 struct 字段
这句话常被误解为“完全不能碰共享变量”,其实 Go 允许共享,但禁止**未经协调的并发读写**。真正的边界在数据所有权转移上。
- 允许:通过 channel 传递指针 ——
ch ,接收方获得唯一所有权,后续所有操作都在该 goroutine 内完成 - 禁止:两个 goroutine 同时对同一个
map[string]int执行m[key]++—— 即使加了sync.Mutex,也违背 CSP 哲学本意;应改为用 channel 把 key 和操作意图发给专属 manager goroutine - 例外:只读共享没问题(如配置
const或初始化后不再修改的var),但一旦涉及写,就必须引入通信契约,而不是靠锁“临时补救”
真正难的不是写出能跑的并发代码,而是判断某个 channel 该不该缓冲、某段 range 有没有隐含的关闭责任、某个 select 是否漏掉了退出信号 —— 这些细节没有银弹,全靠对 CSP 中“进程间通信必须显式建模”这一原则的持续校验。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











