go語(yǔ)言最重要的特點(diǎn)就是原生支持并發(fā)————goroutine也物。而用到并發(fā)宫屠,就不得不考慮數(shù)據(jù)安全的問(wèn)題列疗。Go語(yǔ)言里有兩種方式實(shí)現(xiàn)并發(fā)安全。
以下是go官網(wǎng)上對(duì)于內(nèi)存模型的建議:
Advice
Programs that modify data being simultaneously accessed by multiple goroutines must serialize such access.
To serialize access, protect the data with channel operations or other synchronization primitives such as those in the sync and sync/atomic packages.
If you must read the rest of this document to understand the behavior of your program, you are being too clever. Don’t be clever.
1. sync/atomic
sync/atomic包提供了底層的原子級(jí)內(nèi)存操作抵栈。該包的函數(shù)分為四個(gè)系列: Load,Store古劲,Add斥赋,Swap产艾,CompareAndSwap,分別用來(lái)進(jìn)行整形變量的加載闷堡,保存,加減杠览,交換和比較交換操作弯菊。
這些函數(shù)必須謹(jǐn)慎地保證正確使用踱阿。除了某些特殊的底層應(yīng)用钦铁,使用通道或者sync包的函數(shù)/類型實(shí)現(xiàn)同步更好才漆。
2. sync
2.1 什么情況下要使用鎖
當(dāng)可能存在以下情況:同時(shí)有多個(gè)線程訪問(wèn)同一段內(nèi)存牛曹,且其中至少有一個(gè)線程的操作是寫操作栽烂。
滿足以上條件,就應(yīng)該果斷加鎖腺办。加鎖的操作是幾十納秒級(jí)別的,開銷基本可以忽略书妻。而如果沒(méi)有加鎖導(dǎo)致數(shù)據(jù)不一致甚至crash,損失就大了躲履。以上條件對(duì)使用atomic包依然成立聊闯。
2.2 example
sync包的鎖包括互斥鎖和讀寫互斥鎖。
簡(jiǎn)單寫了一個(gè)讀寫互斥鎖的例子菱蔬,需要注意的是,不僅寫的時(shí)候要加鎖(或使用atomic操作)拴泌,讀的時(shí)候也要加鎖(或使用atomic操作)。
type smtx struct {
lock sync.RWMutex
data string
}
var s smtx
func write() {
s.Lock()
defer s.Unlock()
s.data += "a"
}
func read() {
s.RLock()
defer s.RUnlock()
fmt.Println(s.data)
}
3. channel
Go語(yǔ)言有一句流行的黑話:不要通過(guò)共享內(nèi)存進(jìn)行通信, 通過(guò)通信共享內(nèi)存 (Don't communicate by sharing memory, insted share memory by communicating)箭昵。通過(guò)通信來(lái)共享內(nèi)存回季,可以更大程度的解耦代碼,提高代碼的可讀性和可維護(hù)性泡一。雖然增加了一點(diǎn)內(nèi)存開銷颤殴,但是大大降低編程復(fù)雜度。
說(shuō)一句題外話瘾杭,微服務(wù)架構(gòu),也是利用消息隊(duì)列來(lái)實(shí)現(xiàn)模塊之間的解偶贤笆。和這句話有相通之處。
channel本質(zhì)上就是通過(guò)內(nèi)存隊(duì)列芥永,一次性只處理一個(gè)消息,從而實(shí)現(xiàn)了訪問(wèn)的序列化板辽,避免了數(shù)據(jù)競(jìng)爭(zhēng)(data race)棘催。
很多時(shí)候劲弦,編譯器會(huì)做一些神奇的優(yōu)化醇坝,導(dǎo)致意想不到的數(shù)據(jù)沖突,所以画畅,只要滿足“同時(shí)有多個(gè)線程訪問(wèn)同一段內(nèi)存宋距,且其中至少有一個(gè)線程的操作是寫操作”這一條件,就需要作并發(fā)安全方面的處理谚赎。
最后,推薦一篇關(guān)于數(shù)據(jù)競(jìng)爭(zhēng)文章, 說(shuō)明了沸版,即使在所謂良性數(shù)據(jù)競(jìng)爭(zhēng)兴蒸,也可能出問(wèn)題。