這篇文章給大家介紹Go 語言中協(xié)程通信實(shí)現(xiàn)的共享內(nèi)存是怎樣的,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
創(chuàng)新互聯(lián)于2013年開始,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項(xiàng)目網(wǎng)站設(shè)計(jì)制作、做網(wǎng)站網(wǎng)站策劃,項(xiàng)目實(shí)施與項(xiàng)目整合能力。我們以讓每一個(gè)夢想脫穎而出為使命,1280元貢嘎做網(wǎng)站,已為上家服務(wù),為貢嘎各地企業(yè)和個(gè)人服務(wù),聯(lián)系電話:028-86922220
通過 goroutine 基于協(xié)程在 Go 語言中實(shí)現(xiàn)并發(fā)編程,從語法結(jié)構(gòu)來說,Go 語言的協(xié)程是非常簡單的,只需要通過 go
關(guān)鍵字聲明即可,難點(diǎn)在于并發(fā)引起的不確定性,以及為了協(xié)調(diào)這種不確定性在不同協(xié)程間所要進(jìn)行的通信,常見的并發(fā)通信模型有兩種:共享內(nèi)存和消息傳遞。
下面,我們先來看看如何通過共享內(nèi)存來實(shí)現(xiàn) Go 協(xié)程通信,并通過協(xié)程通信來重構(gòu)上篇教程的代碼,實(shí)現(xiàn)應(yīng)用程序的優(yōu)雅退出,新建一個(gè) memory.go
,并編寫代碼如下:
package main
import (
"fmt"
"runtime"
"sync"
)
var counter int = 0
func add(a, b int, lock *sync.Mutex) {
c := a + b
lock.Lock()
counter++
fmt.Printf("%d: %d + %d = %d\n", counter, a, b, c)
lock.Unlock()
}
func main() {
start := time.Now()
lock := &sync.Mutex{}
for i := 0; i < 10; i++ {
go add(1, i, lock)
}
for {
lock.Lock()
c := counter
lock.Unlock()
runtime.Gosched()
if c >= 10 {
break
}
}
end := time.Now()
consume := end.Sub(start).Seconds()
fmt.Println("程序執(zhí)行耗時(shí)(s):", consume)
}
為了精確判斷主協(xié)程退出時(shí)機(jī)問題,我們需要在所有子協(xié)程執(zhí)行完畢后通知主協(xié)程,主協(xié)程在收到該信號后退出程序,通過共享內(nèi)存的方式我們引入了一個(gè)全局的 counter
計(jì)數(shù)器,該計(jì)數(shù)器被所有協(xié)程共享,每執(zhí)行一次子協(xié)程,該計(jì)數(shù)器的值加 1,當(dāng)所有子協(xié)程執(zhí)行完畢后,計(jì)數(shù)器的值應(yīng)該是 10,我們在主協(xié)程中通過一個(gè)死循環(huán)來判斷 counter
的值,只有當(dāng)它大于等于 10 時(shí),才退出循環(huán),進(jìn)而退出整個(gè)程序。
此外,由于 counter
變量會被所有協(xié)程共享,為了避免 counter
值被污染(兩個(gè)協(xié)程同時(shí)操作計(jì)數(shù)器),我們還引入了鎖機(jī)制,即 sync.Mutex
,這是 Go 語言標(biāo)準(zhǔn)庫提供的互斥鎖,當(dāng)一個(gè) goroutine 調(diào)用其 Lock()
方法加鎖后,其他 goroutine 必須等到這個(gè) goroutine 調(diào)用同一個(gè) sync.Mutex
的 Unlock()
方法解鎖才能繼續(xù)訪問這個(gè) sync.Mutex
(通過指針傳遞到子協(xié)程,所以整個(gè)應(yīng)用持有的是同一個(gè)互斥鎖),我們可以通過這種方式保證所有 lock.Lock()
與 lock.Unlock()
之間的代碼是以同步阻塞方式串行執(zhí)行的,從而保證對 counter
進(jìn)行讀取和更新操作時(shí),同時(shí)只有一個(gè)協(xié)程在操作它(既保證了操作的原子性)。
最后,我們還統(tǒng)計(jì)了整個(gè)程序執(zhí)行時(shí)間。
當(dāng)我們執(zhí)行這段代碼時(shí),打印結(jié)果如下:
可以看到,實(shí)際執(zhí)行時(shí)間遠(yuǎn)遠(yuǎn)小于1秒,這樣一來,程序的整體執(zhí)行效率相比于上篇教程的實(shí)現(xiàn)快了將近1萬倍。
不過,代碼也因此變得更復(fù)雜,更難以維護(hù),這還只是個(gè)簡單的加法運(yùn)算實(shí)現(xiàn),就要寫這么多代碼,要引入共享變量,還要引入互斥鎖來保證操作的原子性,對于更加復(fù)雜的業(yè)務(wù)代碼,如果到處都要加鎖、解鎖,顯然對開發(fā)者和維護(hù)者來說都是噩夢,Go 語言既然以并發(fā)編程作為語言的核心優(yōu)勢,當(dāng)然不至于將這樣的問題用這么繁瑣的方式來解決。
前面我們說,除了共享內(nèi)存之外,還可以通過消息傳遞來實(shí)現(xiàn)協(xié)程通信,Go 語言本身的編程哲學(xué)也是「Don’t communicate by sharing memory, share memory by communicating」,所以實(shí)際上,我們在 Go 語言并發(fā)編程實(shí)踐中,使用的都是基于消息傳遞的方式實(shí)現(xiàn)協(xié)程之間的通信。
在消息傳遞機(jī)制中,每個(gè)協(xié)程是獨(dú)立的個(gè)體,并且都有自己的變量,與共享內(nèi)存不同的是,在不同協(xié)程間這些變量不共享,每個(gè)協(xié)程的輸入和輸出都只有一種方式,那就是消息,這有點(diǎn)類似于進(jìn)程:每個(gè)進(jìn)程都是獨(dú)立的,不會被其他進(jìn)程打擾,不同進(jìn)程間靠消息來通信,它們不會共享內(nèi)存。
關(guān)于Go 語言中協(xié)程通信實(shí)現(xiàn)的共享內(nèi)存是怎樣的就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。