一、Goroutine協程:協程就是go提供的輕量級的獨立運算過程,比線程還輕;建立一個協程,就是使用go關鍵字,後面跟上要運行的函數異步
案例要求:1)、先計算1000如下全部可以被3整除的整數的和Aide
2)、而後計算1000如下全部可以被5整除的整數和B函數
3)、而後再計算1000如下全部可以被3和5整除的整數和Cspa
4)、使用A+B-C獲得最後結果線程
案例中,使用go關鍵字建立一個協程,協程函數內使用channel(chan數據,相似隊列,在取chan中數據時,若是爲空,會阻塞,直到chan中有數據)存儲數據code
package main import ( "fmt" "runtime" "time" ) func get_sum_of_divisible(num int, divider int, resultChan chan int) { sum := 0 for value := 0; value < num; value++ { if value%divider == 0 { sum += value } } resultChan <- sum } func main() { runtime.GOMAXPROCS(runtime.NumCPU()) LIMIT := 1000 //用於被15除結果 job1 := make(chan int, 1) //用於被3,5除結果 job2 := make(chan int, 2) t_start := time.Now() go get_sum_of_divisible(LIMIT, 15, job1) go get_sum_of_divisible(LIMIT, 3, job2) go get_sum_of_divisible(LIMIT, 5, job2) sum15 := <-job1 sum3, sum5 := <-job2, <-job2 sum := sum3 + sum5 - sum15 t_end := time.Now() fmt.Println(sum) fmt.Println(t_end.Sub(t_start)) }
二、Channel通道:提供了協程之間的通訊方式以及運行同步機制協程
案例:假設訓練定點投籃和三分投籃,教練在計數blog
若是向channel裏面寫信息,必須有配對的取信息的一端;假如把下面的go count(c)註釋掉,則不會有打印數據three
package main import ( "fmt" "strconv" "time" ) func fixed_shooting(msg_chan chan string) { i := 1 for { msg_chan <- "fixed shooting" var str string = strconv.Itoa(i) fmt.Println("continue fixed shooting..." + str) i++ } } func count(msg_chan chan string) { for { msg := <-msg_chan fmt.Println(msg) time.Sleep(time.Second * 1) } } func main() { var c chan string c = make(chan string) go fixed_shooting(c) go count(c) var input string fmt.Scanln(&input) }
加一個三分投籃方法,能夠看出,寫入channel中的數據,必須讀取出來才能再次寫入,若是沒有讀取出來,再次寫入會失敗隊列
package main import ( "fmt" "strconv" "time" ) func three_point_shooting(msg_chan chan string) { i := 1 for { var str string = strconv.Itoa(i) msg_chan <- "three point shooting--" + str i++ } } func fixed_shooting(msg_chan chan string) { i := 1 for { var str string = strconv.Itoa(i) msg_chan <- "fixed shooting--" + str i++ } } func count(msg_chan chan string) { for { msg := <-msg_chan fmt.Println(msg) time.Sleep(time.Second * 1) } } func main() { var c chan string c = make(chan string) go fixed_shooting(c) go three_point_shooting(c) go count(c) var input string fmt.Scanln(&input) }
結果圖以下,結果是交替輸出的,也就是channel中輸入的必須輸出後才能再次輸入
三、Channel通道方向
var c chan string 可讀寫channel,可寫入也可讀取
var c chan<- string 只寫channel,只能寫入
var c <-chan string 只讀channel,只能讀取
四、多通道(Select)
案例中,select依次檢查每一個channel是否有消息傳遞過來,若是有就輸出;若是同時有多個消息到達,select隨機選擇一個channel來從中讀取消息;若是沒有一個channel有消息到達,那麼select語句就阻塞在這裏一直等待。select 語句也能夠有default片斷,case不符合時會執行default語句片斷。select中case、default相似switch中case、default
下面case中使用了time.After,能夠這樣理解,main函數也是一個channel,time.After讓main阻塞指定時間後,讀出時間消息(案例中沒有用變量存儲返回的時間)
package main import ( "fmt" "time" ) func fixed_shooting(msg_chan chan string) { var times = 3 var t = 1 for { if t <= times { msg_chan <- "fixed shooting" } t++ time.Sleep(time.Second * 1) } } func three_point_shooting(msg_chan chan string) { var times = 3 var t = 1 for { if t <= times { msg_chan <- "three point shooting" } t++ time.Sleep(time.Second * 1) } } func main() { c_fixed := make(chan string) c_3_point := make(chan string) go fixed_shooting(c_fixed) go three_point_shooting(c_3_point) go func() { for { select { case msg1 := <-c_fixed: fmt.Println(msg1) case msg2 := <-c_3_point: fmt.Println(msg2) case <-time.After(time.Second * 5): fmt.Println("timeout check again...") } } }() var input string fmt.Scanln(&input) }
結果圖
五、Channel Buffer通道緩衝區:通常咱們定義的channel都是同步的,也就是說接受端和發送端彼此等待對方OK纔開始。可是若是執行了channel緩衝區大小,那麼消息的發送和接收是異步的,除非channel緩衝區已經滿了
package main import ( "fmt" "strconv" "time" ) func shooting(msg_chan chan string) { var group = 1 for { for i := 1; i <= 10; i++ { msg_chan <- strconv.Itoa(group) + ":" + strconv.Itoa(i) } group++ time.Sleep(time.Second * 5) } } func count(msg_chan chan string) { for { fmt.Println(<-msg_chan) } } func main() { var c = make(chan string, 20) go shooting(c) go count(c) var input string fmt.Scanln(&input) }