并發(fā)編程
并發(fā)編程的優(yōu)勢:
? 并發(fā)編程能夠更客觀的表現(xiàn)問題模型
? 并發(fā)編程能夠充分利用CPU核心優(yōu)勢
? 并發(fā)編程能夠利用CPU與其他硬件固有的異步性
并發(fā)編程的實現(xiàn)模型:
? 多進程 (系統(tǒng)內(nèi)核管理)
? 多線程
? 基于回調(diào)的非阻塞/異步IO
? 協(xié)程
并發(fā)通信模型通常分類:
? 我們將之前線程加共享內(nèi)存的方式稱之為 “共享內(nèi)存系統(tǒng)”?,F(xiàn)在有一種新的系統(tǒng)模型 “消息傳遞系統(tǒng)”。
? Go語言采用消息機制,消息機制認為每個并發(fā)單元都是自包含、獨立的個體,并且有自己的變量,但在不同并發(fā)單元之間這些變量并不共享。每個并發(fā)單元的輸入輸出只有一種,就是消息。Go語言提供的消息通信機制稱為channel
協(xié)程的優(yōu)勢:
與傳統(tǒng)的線程和進程相比,協(xié)程的優(yōu)勢在于輕量級,可以輕松創(chuàng)建百萬個協(xié)程而不會導致系統(tǒng)資源衰竭,而線程和進程最多也只能一萬多個。
channel:
? channel的一般聲明方式
var chanName chan ElementType
var ch chan int
? 聲明一個map 元素為bool類型
var m map[string] chan bool
? 定義一個channel
ch := make(chan int)
? channel 常見用法就是讀寫,將一個數(shù)據(jù)寫入channel的語法:
ch <- value 向channel中寫入數(shù)據(jù)會導致程序阻塞,直到其他goroutine從這個channel中讀取數(shù)據(jù)。從channel中讀取數(shù)據(jù)的語法是:
value := <- ch 如果channel之前沒有寫入數(shù)據(jù),那么從channel中讀取數(shù)據(jù)也會導致程序阻塞,直到該channel寫入數(shù)據(jù)為止。
select:
select 的用法同switch語句相似,與之相比,select多了很多限制,select語句塊中的case 后邊必須是一個IO操作。
select{
case <-chan1 :
// 如果chan1成功讀取數(shù)據(jù),則進行該case操作
case chan2<-1 :
// 如果chan2成功寫入數(shù)據(jù),則進行該case操作
default:
// 如果上邊兩case都不成立,進行該操作
}
緩沖機制:
之前創(chuàng)建的都是不帶緩沖的channel,這種對于單數(shù)據(jù)的場景還可以應付,但是對于需要持續(xù)大數(shù)據(jù)量的場景下就不合適了,需要加入緩沖區(qū)來達到一種消息隊列的效果。
ch := make(chan int , 1024) 創(chuàng)建一個緩沖區(qū)大小為1024的int 類型channel。在這種具有緩沖區(qū)的channel下,即使沒有數(shù)據(jù)的讀取方,也可以持續(xù)寫入,在緩沖區(qū)沒有填滿前不會發(fā)生阻塞。
超時機制:
在并發(fā)編程中最需要注意的就是超時問題,即當channel中寫數(shù)據(jù)時,channel已經(jīng)滿了,或者從channel中讀取數(shù)據(jù)時,channel中為空,如果不正確處理這些問題,就會導致goroutine鎖死。Go語言沒有直接提供超時處理機制,但是我們可以使用select機制。因為select機制就是只要有一個case已經(jīng)完成,程序就會繼續(xù)往下走,而不會考慮其他case情況。
select {
// 從chs[1] 中讀取數(shù)據(jù)
case <-chs[1]:
// 一直沒有從chs[1]中讀取到數(shù)據(jù),但是從timeout中讀取到數(shù)據(jù),那么程序接著執(zhí)行
case <-timeout:
}