go vet 报 `passing lock by value: sync.Mutex`,代码能编译也能跑,只是加锁之后并发计数仍偶尔少几个,压测时结果总比预期小,怀疑锁根本没有生效。第一次遇到会往复杂处想,其实漏掉的多是个小前提。

go vet ./...
go vet -copylocks ./...
grep -n 'sync.Mutex' -r .

结构体按值传参或按值返回时把 Mutex 一起复制了一份,方法锁的是副本,原对象上的字段完全没被保护,锁定形同虚设,而且这种错误编译器不会拦。这一点先确认清楚,后面就不用反复试。

「copylocks 锁拷贝」这类改动最怕改一半,回滚脚本先准备好,再动生产。把复现步骤压到三条以内,交给同事也能跑出来,才算真的定位清楚。

改动写完就同步给同事,下一个人踩同一个坑,成本还是你的。

具体做法是,把方法的接收者统一改成指针类型而不是值;传参时统一用指针而不是按值复制整个结构体;对含锁的结构体禁用值赋值和值返回这两种写法。

改完照着核一遍,go vet 不再报锁复制,并发计数在多轮压测下完全一致,一次偏差都没有。

作者 9823189