讓乙個程式併發安全並不需要其中的每乙個具體型別都是併發安全的。實際上併發安全的型別其實是特例而不是普遍存在的,所以僅在文件指出型別是安全的情況下,才可以併發的訪問乙個變數。與之對應的是,匯出的包級別函式通常可以認為是併發安全的。因為包級別的變數無法限制在乙個goroutine內。所以那些修改這些變數的函式必須採用互斥機制。
例如下面**就會存在競態問題導致結果與與其不否
var x int64var wg sync.waitgroup
func add()
wg.done()
}func main()
這時引入鎖至關重要,在go中sync包提供了鎖機制
sync包同步提供基本的同步原語,如互斥鎖。 除了once和waitgroup型別之外,大多數型別都是供低階庫例程使用的。 通過channel和溝通可以更好地完成更高階別的同步。並且此包中的值在使用過後不要拷貝。
sync包中主要有:locker, cond, map, mutex, once, pool,、rwmutex, waitgroup
互斥鎖的模式應用非常廣泛,所以sync包有乙個單獨的mutex型別來支援這種模式,它的lock方法用來獲取令牌(token,此過程也稱為上鎖), unlock方法用於釋放令牌。
var x int64var wg sync.waitgroup
var lock sync.mutex
func add()
wg.done()
}func main()
在lock和unlock之間的**,可以自由的讀取和修改共享變數,這一部分稱為臨界區域。在鎖的持有人呼叫unlock之前,其他的goroutine不能獲取鎖。
在某種情況下,函式只須讀取變數的狀態,所以多個函式可以安全的併發執行。只要在寫入沒有同時就行,在這種場景下,就需要一種特殊的安全鎖,它只允許讀操作可以併發執行,但寫操作需要獲得安全獨享的訪問許可權。
var (x int64
wg sync.waitgroup
lock sync.mutex
rwlock sync.rwmutex
)func write()
func read()
func main()
for i := 0; i < 1000; i++
wg.wait()
end := time.now()
fmt.println(end.sub(start))
}
延遲是乙個昂貴的初始化步驟到有實際需求的時刻是乙個很好的實踐。而sync.once是乙個可以被多次呼叫但是只執行一次,若每次呼叫do時傳入引數f不同,但是只有第乙個才會被執行。
sync.once有乙個 do方法。示例如下
var once sync.onceoncebody := func()
done := make(chan bool)
for i := 0; i < 10; i++ ()
}for i := 0; i < 10; i++
執行雖然呼叫了10次,但是只執行了1次。btw:這個東西可以用來寫單例。
package singletonimport (
"sync"
)type singleton struct {}
var instance *singleton
var once sync.once
func getinstance() *singleton
})return instance
}
waitgroup 用來等待一組goroutines的結束,在主goroutine裡宣告,並且設定要等待的goroutine的個數,每個goroutine執行完成之後呼叫 done,最後在主goroutines 裡wait即可。waitgroup含有三種方法
func (wg *waitgroup) add(d int) //計數器+dfunc (wg *waitgroup) done() //計數器-1
func (wg *waitgroup) wait() //阻塞直到計數器變為0
乙個簡單的例子
var wg sync.waitgroupfunc hello()
func main()
在編寫時即使最大的仔細還會出現併發上的錯誤,幸運的是,go語言在執行時和工具鏈裝備了乙個精緻並易於使用的動態分析工具:競態檢測器。
簡單的把 -race命令列引數加到go build, go run, go test命令裡邊即可使用該功能。它會讓編譯器為你的應用或測試構建乙個修訂後的版本。
競態檢測器會研究事件流,找到那些有問題的案例,即乙個goroutine寫入乙個變數後,中間沒有任何同步的操作,就有另乙個goroutine寫入了該變數。這種案例表明有對共享變數的併發訪問,即資料動態。
競態檢測器報告所有實際執行了的資料競態。它只能檢測到那些在執行時發生的競態,無法用來保證肯定不會發生京態。
有興趣的可以仔細研究。
golang中併發sync和channel
golang中實現併發非常簡單,只需在需要併發的函式前面新增關鍵字 go 但是如何處理go併發機制中不同goroutine之間的同步與通訊,golang 中提供了sync包和channel機制來解決這一問題 sync 包提供了互斥鎖這類的基本的同步原語.除 once 和 waitgroup 之外的型...
golang中併發sync和channel
golang中實現併發非常簡單,只需在需要併發的函式前面新增關鍵字 go 但是如何處理go併發機制中不同goroutine之間的同步與通訊,golang 中提供了sync包和channel機制來解決這一問題 sync 包提供了互斥鎖這類的基本的同步原語.除 once 和 waitgroup 之外的型...
golang中併發sync和channel
golang中實現併發非常簡單,只需在需要併發的函式前面新增關鍵字 go 但是如何處理go併發機制中不同goroutine之間的同步與通訊,golang 中提供了sync包和channel機制來解決這一問題 sync 包提供了互斥鎖這類的基本的同步原語.除 once 和 waitgroup 之外的型...