這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
GO並發
在一個函數調用前加上go關鍵字,這次調用就會在一個新的goroutine中並發執行。
func Add(x, y int) { z := x + y fmt.Println(z)}func main() { for i := 0; i < 10; i++ { go Add(i, i) }}
Go程式從初始化main package並執行main()函數開始,當main()函數返回時,程式退出.且程式並不等待
其他goroutine(非主goroutine)結束。
並發通訊
GO語言既以並發編程作為語言的最核心優勢,提供了一種通訊模型,即以訊息機制而非共用記憶體作為通訊方式。訊息機制認為每個並發單元是自包含的、獨立的個體,並且都有自己的變數,但在不同並發單元間這些變數不共用。每個並發單元的輸入和輸出只有一種,那就是訊息。這有點類似於進程的概念,每個進程不會被其他進程打擾,它只做好自己的工作就可以了。不同進程間靠訊息來通訊,它們不會共用記憶體。
Go語言提供的訊息通訊機制被稱為channel “不要通過共用記憶體來通訊,而應該通過通訊來共用記憶體。”
channel
channel是Go語言在語言層級提供的goroutine間的通訊方式。channel是類型相關的
chan聲明
var chanName chan ElementType如:
var chint chan int //什麼一個int類型的chanvar mch map[string] chan bool //聲明一個map,其元素為boolvar arrch [10]chan int //定義一個
執行個體
func Count(ch chan int) { ch <- 1 fmt.Println("Counting")}func main() { chs := make([]chan int, 10) for i := 0; i < 10; i++ { chs[i] = make(chan int) go Count(chs[i]) } for _, ch := range(chs) { <-ch }}
定義channel直接使用內建的函數make()即可:
ch := make(chan int)
channel基本用法寫入
<span style="white-space:pre"></span>ch < 1
向channel寫入資料通常會導致程式阻塞,直到有其他goroutine從這個channel中讀取資料
讀出
i := < ch
如果ch沒有資料也會導致程式阻塞,直到有資料寫入ch
但是,對ch的阻塞,可以利用ch的緩衝機制以及select來靈活出來
緩衝機制帶緩衝的channel適合於需連續傳輸大量資料的情境,定義一個帶緩衝的channel,只需將容量傳入make的第二個參數即可
c := make(chan int, 1024) //建立了一個大小為1024的整形chan,寫入在緩衝區滿前 不會阻塞
channel是可傳遞的
單向channel單向channel只能用於發送或者接收資料。聲明
var ch1 chan int // ch1是一個正常的channel,不是單向的var ch2 chan<- float64// ch2是單向channel,只用於寫float64資料var ch3 <-chan int // ch3是單向channel,只用於讀取int資料
初始化channel可以在單向channel和雙向channel之間進行轉換,channel本身就是GO的原生類型,因此可被傳遞,也可類型轉換
ch4 := make(chan int)ch5 := <-chan int(ch4) // ch5就是一個單向的讀取channelch6 := chan<- int(ch4) // ch6 是一個單向的寫入channel
關閉channel
直接用 close即可
close(ch)
判斷channel是否已關閉,可以用多值返回讀,如果第二個bool傳回值是false則表示ch已經被關閉
x, ok := <-ch
select
用來監控一系列檔案控制代碼發生的IO操作,一旦有其中一個控制代碼發生IO操作,則被返回GO在語言層級支援select代碼結構大致如:
select {<span style="white-space:pre"></span>case <-chan1:<span style="white-space:pre"></span>// 如果chan1成功讀到資料,則進行該case處理語句<span style="white-space:pre"></span>case chan2 <- 1:<span style="white-space:pre"></span>// 如果成功向chan2寫入資料,則進行該case處理語句<span style="white-space:pre"></span>default:<span style="white-space:pre"></span>// 如果上面都沒有成功,則進入default處理流程}
其中每個case必須是一個檔案控制代碼操作結合for可實現迴圈檢測
ch := make(chan int, 1)for {<span style="white-space:pre"></span>select {<span style="white-space:pre"></span>case ch <- 0:<span style="white-space:pre"></span>case ch <- 1:<span style="white-space:pre"></span>}<span style="white-space:pre"></span>i := <-ch<span style="white-space:pre"></span>fmt.Println("Value received:", i)}