竞态,就是多个协程同时访问临界区,由并发而产生的数据不同步的状态。
这个说的有点low,没办法,我就是这么表达的,官方的请度娘。
先上代码:
输出:
为何不是1000?就是因为竞态,发生竞态后,最终的输出是以最后一个协程执行的结果为准,但最后一个协程有一定的随机性,不是先跑先完。
改一下代码:
输出:
因为加了锁,这1000个协程是按照队列的顺序执行12行,所以稳定输出 final value of x 1000
再看:
输出:
照样稳定输出 final value of x 1000,因为信道的读和写都具有排他性,虽然不是锁住临界区,但是能起到让后来的协程排队的效果。
那么这两种情况怎么选择呢? 引用一个大牛的话:
Mutex vs 信道
通过使用 Mutex 和信道,我们已经解决了竞态条件的问题。那么我们该选择使用哪一个?答案取决于你想要解决的问题。如果你想要解决的问题更适用于 Mutex,那么就用 Mutex。如果需要使用 Mutex,无须犹豫。而如果该问题更适用于信道,那就使用信道。:)
由于信道是 Go 语言很酷的特性,大多数 Go 新手处理每个并发问题时,使用的都是信道。这是不对的。Go 给了你选择 Mutex 和信道的余地,选择其中之一都可以是正确的。
总体说来,当 Go 协程需要与其他协程通信时,可以使用信道。而当只允许一个协程访问临界区时,可以使用 Mutex。
就我们上面解决的问题而言,我更倾向于使用 Mutex,因为该问题并不需要协程间的通信。所以 Mutex 是很自然的选择。
我的建议是去选择针对问题的工具,而别让问题去将就工具。:)