本文摘自网络,作者,侵删。
在之前的文章中,我们详细说了 Go 语言中 goroutine + channel 通过通信的方式来共享内存,从而实现并发编程。
但同时 Go 也提供了传统通过共享变量,也就是共享内存的方式来实现并发。这篇文章会介绍 Go
提供的相关机制。
1. 什么是竞态
在一个 Go 程序运行起来之后,会有很多的 goroutine 同时运行,每个 goroutine 中代码的执行是顺序的,如果我们无法确定两个 goroutine 中代码的执行顺序。就可以说这两个 goroutine 是并发执行的。
如果一段代码无论是顺序执行还是并发执行,结果都是正确的,那就可以说这个代码是并发安全的。
并发不安全的代码出现的问题有多种,比如死锁、活锁、经态等等。死锁和活锁都表示代码已经无法继续执行了,而竞态则表示代码是可以执行的,但是有可能会出现错误的结果。
有一个典型的例子就是向银行账户中存款:
var balance int
func Deposit(amount int) {
balance = balance + amount
}
func Balance() int {
return balance
}
复制代码
假如现在有两个人同时向这个账户中存款,各自存了 100 次:
for i := 0; i < 100; i++ {
go func() {
Deposit(100)
}()
go func() {
Deposit(100)
}()
}
// 休眠一秒,让上面的 goroutine 执行完成
time.Sleep(1 * time.Second)
fmt.Println(Balance())
复制代码
如果程序正确,那么最后的输出应该是 20000,但多次运行,结果可能是 19800、19900 或者其他的值。这个时候,我们就会说这个程序存在数据竞态。
相关阅读 >>
手撸Golang 基本数据结构与算法 图的最短路径 贝尔曼-福特算法
更多相关阅读请进入《Go》频道 >>

Go语言101
一个与时俱进的Go编程知识库。