老生常谈一下,golang中没有线程概念,只有协程。不是搞旅游的那个携程哈。 同时,人家go官方团队也是明确地警告gopher了,不要自做聪明,老老实实地用同步库(sync)、原子库(atomic)以及chan来实现无竞争(data-race-free) go程序就可以了。
听人劝,吃饱饭。
严格按照人家说的上面三种机制,是不用担心竞争的。下面的内容,给同样是“好奇害死人”的技工看的。
Happens-Before机制
golang中的协程同步,只要严格遵守该偏序机制(Partial Order),就能保证竞争安全,或者说无竞争。
Happens-Before主要分为两种具体的实现机制:
- 顺序先发生(Sequential-Before)
- 同步先发生(Synchronization-Before)
顺序先发生(Sequential-Before)
顺序先发生,就是说,同一个协程内的一个段代码,执行顺序从上往下,顺序执行,如:
func someMethod() {
var a = "helloworld" // 1
fmt.Println(a) // 2
}
上述代码,第一行代码一定是在第二行代码之前执行。所以,这两行代码的执行顺序,是可以保证两者无竞争的,或者换句话说,第二行代码fmt.Println(a)的时候,变量a是一定有值的。
func someMethod2() {
fmt.Println(a) // 3
}
反之,倘若有另一个方法someMethod2在一个与someMethod不同的协程里执行,那代码3就与代码1或3与2之间,就无任何Sequential-Before的关系了。
他们能有的,只可能是Synchronization-Before的关系
同步先发生(Synchronization-Before)
同步先发生,是指两行代码,在不同的协程运行时,因为golang自己的机制、或者因为sync包的功能等原因,导致一个协程的内代码一定先于(或者迟于)另一个协程的某段代码执行,该关系就叫做Synchronized-Before:同步先发生。
golang自带的一些Synchronized-Before机制,如:
- 如果包
p引入了q,则q包的init函数,在包p任何代码被执行前,完成执行 - 一个go程序里,所有的
init函数执行完成后才会执行main.main()函数 go someMethod():通过关键字go启动的某个协程的场景中,一定是先执行完go someMethod()这段代码,然后在新协程里才会开始执行someMethod的内容。这个多少有点废话,但是官方就是这么严谨。go关键字启动的新协程,它的执行完成与否,不与任何其他内建机制或事件存在Synchronized-Before关系