這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
整理自《go語言編程》-第四章
1、並發基礎
多進程:多進程是在作業系統層面進行並發的基本模式。同時也是開銷最大的模式。在Linux平台上,很過工具鏈正是採用這種模式在工作。比如某個Web伺服器,它會有專門的進程負責網路連接埠的監聽和連結管理,還會有專門的進程負責事務和運算。這種方法的好處在於簡單、進程間互不影響,壞處是系統開銷大,因為所有的進程都是由核心管理的。
多線程:多線程在大部分作業系統上都屬於系統層面的併發模式,也是我們使用最多的最有效一種模式。目前,我們所見的幾乎所有工具鏈都會使用這種模式。它比多進程的開銷小很多,但是其開銷依舊比較大,且在高併發模式下,效率會有影響。
基於回調的非阻塞/非同步IO:這種架構的誕生實際上來源於月多線程模式的危機。在很多高並發伺服器開發實踐中,使用多線程模式會很快耗盡伺服器的記憶體和CPU資源。二這種模式通過事件驅動的方式使用非同步IO,伺服器持續運轉,且儘可能少用線程,降低開銷,它目前在Node.js中得到了很好的實踐,但是使用這種模式,編程比多線程要複雜,因為它把流程做了分割,對於問題的本身反應不夠自然。
協程:協程(coroutine)本質上一種使用者態線程,不需要作業系統來進行搶佔式調度,且在真正的實現中寄存於線程中,因此,系統開銷極小,可以有效提高線程的任務並發性,而避免多線程的缺點。使用協程的優點是編程簡單,結構清晰;缺點是需要語言的支援,如果不支援,則需要使用者在程式中自行實現調度器。
2、協程
執行體是個抽象的概念,在作業系統層面有多個概念與之對應,比如作業系統自己掌握的進程(process)、進程內的線程(thread)以及進程內的協程(coroutine,也叫輕量級線程)
多數語言在文法層面並不直接支援協程,而是通過庫的方式支援。
Go語言在語言層級支援輕量級線程,叫goroutine。
3、Goroutine
Goroutine是Go語言中的輕量級線程實現,由Go運行時(runtime)管理。
.go:關鍵字,函數調用前加go關鍵字,這次調用就會在一個新的goroutine中並發執行。當被調用的函數返回時,這個goroutine也自動結束。如果不是使用channel接收的話,這個函數的傳回值將會被丟棄。
4、並發通訊
不管是什麼平台、什麼程式設計語言並發都是一個大話題。
在工程上,有兩種最常見的並發通訊模型:共用資料和訊息。
共用資料:多個並發單元分別儲存對同一個資料的引用,實現對該資料的共用。被共用的資料可能有多種形式,比如記憶體資料區塊、磁碟檔案、網路資料等。在實際工程應用中最常見的就是共用記憶體。
Go語言社區:不要通過共用記憶體來通訊,而應該通過通訊來共用記憶體。
Go語言提供的是另一種通訊模型,即以訊息機制而非共用記憶體作為通訊方式。
5、Channel
(1)概念
Channel 是Go語言在語言層級提供的goroutine間的通訊方式。我們可以使用channel在兩個或多個goroutine之間傳遞訊息。
Channel是進程內的通訊方式,因此通過channel傳遞對象的過程和調用函數時參數
傳遞的行為比較一致,比如可以傳遞指標等。
Channel是類型相關的,一個channel只能傳遞一種類型的值。
(2)基本文法
聲明形式:
Var chanName chan ElementType
例子:var ch chan int
定義channel:
Ch := make(chan int)
向channel中寫入資料:
Ch <- value
從channel中讀取資料:
Value := <- ch
(3)select
Go語言直接在語言層級支援select關鍵字,用於處理非同步IO問題。
Select {
Case <- chan1:
//如果chan1成功讀到資料,則進行該case處理語句
Case chan2 <-1:
//如果成功向chan2寫入資料,則進行該case處理語句
Default:
//如果上面的都沒有成功,則進入default處理流程
}
(4)緩衝機制
建立一個帶緩衝區的channel:
C := make(chan int, 1024)
(5)逾時機制
在並發編程的通訊過程中,最需要處理的就是逾時問題,即向channel寫入資料時發現channel已滿,或者從channel試圖讀取資料時發現channel為空白。如果不正確處理這個問題,可能會導致整個goroutinue鎖死。
Go語言沒有提供直接的逾時處理機制,但可以利用select機制,可以解決逾時問題。
(6)channel的傳遞
注意:在go語言中channel本身也是一個原生類型,與map之類的類型地位一樣,因此channel本身在定義後也可以通過channl來傳遞。
(7)單向channel
單向channel只能用於發送或者接收資料。
從設計者的角度,所有的代碼都應該遵循“最小許可權的原則”
(8)關閉channel
使用go語言的內建函數:close(ch)
在讀取時使用多重傳回值的方式可以判斷: x, ok := <-ch
6、讓出時間片
每個goroutine中控制何時主動讓出時間片給其他goroutine,可以使用runtime包中的Gosched()函數實現。
7、同步
Go 語言套件中的sync包提供兩種鎖類型:sync.Mutex 和sync.RWMutex.
8、全域唯一性操作
Go語言提供一個Once類型來保證全域唯一性操作。