說到go語言最厲害的是什么就不得不提到并發(fā),并發(fā)是什么?,與并發(fā)相關(guān)的并行又是什么?
并發(fā):同一時間段內(nèi)執(zhí)行多個任務(wù)
并行:同一時刻執(zhí)行多個任務(wù)
我們提供的服務(wù)有:成都網(wǎng)站建設(shè)、成都網(wǎng)站制作、微信公眾號開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、紅山ssl等。為近1000家企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的紅山網(wǎng)站制作公司
go語言原生支持并發(fā),可以用go關(guān)鍵字快速的讓一個函數(shù)創(chuàng)建為goroutine協(xié)程,也可以創(chuàng)建多個goroutine去執(zhí)行相同的函數(shù)。
sync.WaitGroup可以用來實現(xiàn)goroutine的同步
例如:
var wg sync.WaitGroup
func hello(i int) {
defer wg.Done() // goroutine結(jié)束就-1
fmt.Println("Hello Goroutine!", i)
}
func main() {
for i := 0; i < 10; i++ {
wg.Add(1) // 啟動一個goroutine就+1
go hello(i)
}
wg.Wait() // 等待所有登記的goroutine都結(jié)束
}
最終打印出來的順序是亂序,因為goroutine是并發(fā)操作。
goroutine實際上就是go中的協(xié)程,在go語言中可以起成千上萬個goroutine協(xié)程來進(jìn)行并發(fā)編程
goroutine的調(diào)度基于GMP模型
go原生提供并發(fā)原語goroutine和channel為構(gòu)造并發(fā)提供了一種優(yōu)雅而簡單的方式,go沒有顯示的利用鎖來控制并發(fā)安全,而是鼓勵提倡通過通信共享內(nèi)存而不是通過共享內(nèi)存而實現(xiàn)通信。
Go語言中原子操作由內(nèi)置的標(biāo)準(zhǔn)庫sync/atomic提供。
這些功能需要非常小心才能正確使用。 除特殊的底層應(yīng)用程序外,同步更適合使用channel或sync包的功能。 通過消息共享內(nèi)存; 不要通過共享內(nèi)存進(jìn)行通信。
互斥鎖是一種常用的共享資源訪問的方法,它能夠保證同時只有一個goroutine可以訪問資源。Go語言中使用sync包的Mutex類型來實現(xiàn)互斥鎖。
go在1.8默認(rèn)使用自旋模式,當(dāng)試圖獲取已經(jīng)被持有的鎖時,如果本地隊列為空并且 P 的數(shù)量大于1,goroutine 將自旋幾次(用一個 P 旋轉(zhuǎn)會阻塞程序)。自旋后,goroutine park。在程序高頻使用鎖的情況下,它充當(dāng)了一個快速路徑。
go在1.9新增了Starving模式,當(dāng)自旋模式搶到鎖,表示有協(xié)程釋放了鎖,如果waiter>0,即有阻塞等待的協(xié)程,會釋放信號量來喚醒協(xié)程,當(dāng)協(xié)程被喚醒后,發(fā)現(xiàn)Locked=1,鎖又被搶占,則又會阻塞,但在阻塞前會判斷自上次阻塞到本次阻塞經(jīng)歷了多長時間,如果超過1ms的話,會將Mutex標(biāo)記為"饑餓"模式,然后再阻塞。當(dāng)被標(biāo)記為饑餓狀態(tài)時,unlock 方法會 handsoff 把鎖直接扔給第一個等待者。
在饑餓模式下,自旋也被停用,因為傳入的goroutines 將沒有機(jī)會獲取為下一個等待者保留的鎖。
互斥鎖是完全互斥的,但是有很多場景下讀多寫少,因此我們并發(fā)去讀取一個資源而不涉及到資源修改的時候是完全沒必要加鎖的,這種情況下讀寫鎖是一種更好的選擇。
讀寫鎖分為讀鎖和寫鎖,讀鎖與讀鎖兼容,讀鎖與寫鎖互斥,寫鎖與寫鎖互斥。
ErrGroup是 Go 官方提供的一個同步擴(kuò)展庫??梢詫⒁粋€大任務(wù)拆分成幾個小任務(wù)并發(fā)執(zhí)行,提高程序效率。sync.ErrGroup在sync.WaitGroup功能的基礎(chǔ)上,增加了錯誤傳遞,以及在發(fā)生不可恢復(fù)的錯誤時取消整個goroutine集合,或者等待超時
go語言為了降低GC壓力引入了sync.Pool對象池用來保存和復(fù)用臨時對象。sync.Pool是可伸縮的,并發(fā)安全的。其大小僅受限于內(nèi)存的大小。sync.pool對象池比較適合用來存儲一些臨時切狀態(tài)無關(guān)的數(shù)據(jù),但是不適合用來做連接池,因為存入對象池中的值有可能會在垃圾回收時被刪除掉
在go的1.13版本中引入了victim cache,會將pool內(nèi)數(shù)據(jù)拷貝一份,避免GC將其清空,即使沒有引用的內(nèi)容也可以保留最多兩輪GC.
channel是一種類型安全的消息隊列,用以充當(dāng)兩個goroutine之間的消息通道。go語言的并發(fā)模型是CSP(Communicating Sequential Processes),提倡通過通信共享內(nèi)存而不是通過共享內(nèi)存而實現(xiàn)通信。
go語言中的channel是一種特殊的類型,遵循先入先出的規(guī)則,保證數(shù)據(jù)的收發(fā)順序。
//創(chuàng)建語法
ch := make(chan int)
無緩沖通道沒有容量,因此無緩沖的通道只有在有接收者的時候才能發(fā)送,否則會形成死鎖,相反如果接收操作先執(zhí)行,接收方的goroutine將阻塞,直到另一個goroutine在該通道上發(fā)送一個值。
func main() {
ch := make(chan int)
go func() {
fmt.Println(<-ch)
}()
ch <- 10
}
無緩沖管道的本質(zhì)是為保證同步
//創(chuàng)建語法
ch := make(chan int, 10) //創(chuàng)建緩沖為10的通道
只要通道的容量大于零,那么該通道就是有緩沖的通道,通道的容量表示通道中能存放元素的數(shù)量,當(dāng)通道的容量已滿時將會阻塞發(fā)送者使其等待緩沖通道可用,而當(dāng)緩沖通道為空的時候會阻塞接收者使其等待資源被發(fā)送。
channel內(nèi)置的len函數(shù)可以獲取通道內(nèi)元素的數(shù)量,使用cap函數(shù)獲取通道的容量。
https://www.cnblogs.com/lxmhhy/p/.html
https://blog.csdn.net/liangzhiyang/article/details/
https://www.cnblogs.com/sunsky303/p/.html
https://zhuanlan.zhihu.com/p/
https://zhuanlan.zhihu.com/p/
https://www.bilibili.com/read/cv/
https://pkg.go.dev/golang.org/x/sync/errgroup
https://mp.weixin.qq.com/s/NcrENqRyK9dYrOBBI0SGkA
https://www.jianshu.com/p/8fbbf6c012b2
https://www.jianshu.com/p/24ede9e
https://www.liwenzhou.com/posts/Go/14_concurrence/#autoid-1-4-3