整理自《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機制,可以解決逾時問題。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiM0ETOzQjM3EDMzkDM2EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
(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類型來保證全局唯一性操作。