竞态
竞态的产生是因为多个对象同时访问一个对象的时候就会产生。 最常见的例子是数据库。
互斥锁:sync.Mutex
使用Lock()加锁后,不能再次对其加锁,直到Ulock()后。
有时候编程很难确定在所有的分支中Lock和Unlock都承兑出现了,那我们可以通过defer解决:
在临界区域(Lock和Unlock之间的代码)时延迟执行的Unlock也会正确执行,这在使用recover的情况下尤其重要。当然,defer的执行成本比显示的调用Unlock略大一些,但不足以称为代码不清晰的理由。
在处理并发程序时,永远应当优先考虑清晰度,并且拒绝过早优化。在可以使用的地方,就进来使用defer来让临界区域扩展到函数结尾处。
读写互斥锁: sync.RWMutex
允许只读操作可以并发执行,但写操作需要获得完全独享的访问权限,这种锁称为多读单写锁,Go语言中的sync.RWMutex提供这种功能:
仅在巨大部分goroutine都在获取读锁并且锁竞争比较激烈时(即goroutine一般都需要等待后才能货到锁),RWMutex才有优势。因为RWMutex需要更复杂的内部簿记工作,所以在竞争不激烈时它比普通的互斥所慢
内存同步
延迟初始化: sync.Once
延迟一个昂贵的初始化步骤到有实际需求的时刻是一个很好的时间。预先初始化一个变量会增加程序的启动延时,并且如果时间执行时有可能根本用不上这个变量,那么初始化也不是必须的
竞态检测器
简单的把-race命令行参数加到go build、go run、go test命令里边即可使用该功能。