溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Go 語言中協(xié)程通信實現(xiàn)的共享內(nèi)存是怎樣的

發(fā)布時間:2021-11-15 15:28:18 來源:億速云 閱讀:406 作者:柒染 欄目:大數(shù)據(jù)

這篇文章給大家介紹Go 語言中協(xié)程通信實現(xiàn)的共享內(nèi)存是怎樣的,內(nèi)容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

通過 goroutine 基于協(xié)程在 Go 語言中實現(xiàn)并發(fā)編程,從語法結構來說,Go 語言的協(xié)程是非常簡單的,只需要通過 go 關鍵字聲明即可,難點在于并發(fā)引起的不確定性,以及為了協(xié)調(diào)這種不確定性在不同協(xié)程間所要進行的通信,常見的并發(fā)通信模型有兩種:共享內(nèi)存和消息傳遞。

下面,我們先來看看如何通過共享內(nèi)存來實現(xiàn) Go 協(xié)程通信,并通過協(xié)程通信來重構上篇教程的代碼,實現(xiàn)應用程序的優(yōu)雅退出,新建一個 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í)行耗時(s):", consume)}

為了精確判斷主協(xié)程退出時機問題,我們需要在所有子協(xié)程執(zhí)行完畢后通知主協(xié)程,主協(xié)程在收到該信號后退出程序,通過共享內(nèi)存的方式我們引入了一個全局的 counter 計數(shù)器,該計數(shù)器被所有協(xié)程共享,每執(zhí)行一次子協(xié)程,該計數(shù)器的值加 1,當所有子協(xié)程執(zhí)行完畢后,計數(shù)器的值應該是 10,我們在主協(xié)程中通過一個死循環(huán)來判斷 counter 的值,只有當它大于等于 10 時,才退出循環(huán),進而退出整個程序。

此外,由于 counter 變量會被所有協(xié)程共享,為了避免 counter 值被污染(兩個協(xié)程同時操作計數(shù)器),我們還引入了鎖機制,即 sync.Mutex,這是 Go 語言標準庫提供的互斥鎖,當一個 goroutine 調(diào)用其 Lock() 方法加鎖后,其他 goroutine 必須等到這個 goroutine 調(diào)用同一個 sync.Mutex 的 Unlock() 方法解鎖才能繼續(xù)訪問這個 sync.Mutex(通過指針傳遞到子協(xié)程,所以整個應用持有的是同一個互斥鎖),我們可以通過這種方式保證所有 lock.Lock() 與 lock.Unlock() 之間的代碼是以同步阻塞方式串行執(zhí)行的,從而保證對 counter 進行讀取和更新操作時,同時只有一個協(xié)程在操作它(既保證了操作的原子性)。

最后,我們還統(tǒng)計了整個程序執(zhí)行時間。

當我們執(zhí)行這段代碼時,打印結果如下:

Go 語言中協(xié)程通信實現(xiàn)的共享內(nèi)存是怎樣的

可以看到,實際執(zhí)行時間遠遠小于1秒,這樣一來,程序的整體執(zhí)行效率相比于上篇教程的實現(xiàn)快了將近1萬倍。

不過,代碼也因此變得更復雜,更難以維護,這還只是個簡單的加法運算實現(xiàn),就要寫這么多代碼,要引入共享變量,還要引入互斥鎖來保證操作的原子性,對于更加復雜的業(yè)務代碼,如果到處都要加鎖、解鎖,顯然對開發(fā)者和維護者來說都是噩夢,Go 語言既然以并發(fā)編程作為語言的核心優(yōu)勢,當然不至于將這樣的問題用這么繁瑣的方式來解決。

前面我們說,除了共享內(nèi)存之外,還可以通過消息傳遞來實現(xiàn)協(xié)程通信,Go 語言本身的編程哲學也是「Don’t communicate by sharing memory, share memory by communicating」,所以實際上,我們在 Go 語言并發(fā)編程實踐中,使用的都是基于消息傳遞的方式實現(xiàn)協(xié)程之間的通信。

在消息傳遞機制中,每個協(xié)程是獨立的個體,并且都有自己的變量,與共享內(nèi)存不同的是,在不同協(xié)程間這些變量不共享,每個協(xié)程的輸入和輸出都只有一種方式,那就是消息,這有點類似于進程:每個進程都是獨立的,不會被其他進程打擾,不同進程間靠消息來通信,它們不會共享內(nèi)存。

關于Go 語言中協(xié)程通信實現(xiàn)的共享內(nèi)存是怎樣的就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI