Golang channle管道的基本使用及快速入門
channel(管道)-基本介紹
為什么需要channel?前面使用全局變量加鎖同步來解決goroutine的通訊,但不完美
(1)主線程在等待所有goroutine全部完成的時間很難確定,我們這里設置10秒,僅僅是估算。
(2)如果主線程休眠時間長了,會加長等待時間,如果等待時間短了,可能還有goroutine處于工作狀態(tài),這時也會隨主線程的退出而銷毀。
(3)通過全局變量加鎖同步來實現(xiàn)通訊,也并不利用多個協(xié)程對全局變量的讀寫操作。
(4)上面種種分析都在呼喚一個新的通訊機制channel
import ( "fmt" "sync" "time" ) var ( m = make(map[int]int, 10) //聲明一個全局的互斥鎖 lock是一個全局的互斥鎖 //sync是包 同步的意思 mutex是互斥的意思 lock sync.Mutex ) // test函數(shù)就是計算n的階乘 func test(n int) { res := 1 for i := 1; i <= n; i++ { res = res * i } //將計算結果放到map當中 加鎖 lock.Lock() m[n] = res lock.Unlock() } func main() { //這里開啟多協(xié)程完成任務 for i := 1; i <= 20; i++ { go test(i) } time.Sleep(time.Second * 10) for k, v := range m { fmt.Println(k, v) } }
channel的介紹
(1)channle本質就是一個數(shù)據(jù)結構-隊列,數(shù)據(jù)是先進先出
(2)線程安全,多goroutine訪問時,不需要加鎖,就是說channel本身就是線程安全的(管道是線程安全的,你在對管道讀取的時候不管有多少個協(xié)程在對同一個管道操作,可以放心使用,不會出現(xiàn)錯誤,這些是有編譯器在底層維護的)
(3)channel是有類型的,一個string的channel只能存放string類型數(shù)據(jù)。(如果管道想放int或者float那么可以使用空接口interface類型)
定義/聲明channel nil類型
var 變量名 chan 數(shù)據(jù)類型,舉例:
var intChan chan int (intChan用于存放int數(shù)據(jù)) var mapChan chan map[int]string (mapChan用于存放map[int]string類型) var perChan chan Person var perChan2 chan *Person
說明:
(1)channel是引用類型
(2)channel必須初始化才能寫入數(shù)據(jù),即make后才能使用
(3)管道是有類型的,intChan只能寫入整數(shù)int
channel初始化
說明:使用make進行初始化
var intChan chan int intChan =make(chan int,10)
向channel中寫入(存放)數(shù)據(jù)
var intChan chan int intChan = make(chan int,10) num = 999 intChan <- 10 intChan <- num
如果將channel傳給另外一個函數(shù),那么在這個函數(shù)里面操作的是同一個管道,因為它是引用類型。
package main import "fmt" func main() { var intChan chan int //創(chuàng)建可以存放3個int類型的管道 intChan = make(chan int, 3) //看看intChan是什么 fmt.Printf("initChan的值為=%v\n initChan本身地址為%p\n", intChan, &intChan) //向管道寫入數(shù)據(jù) intChan <- 1 num := 2 intChan <- num //當給管道寫入數(shù)據(jù)的時候,不能超過其容量 //看看管道的長度和cap fmt.Println("長度:", len(intChan), "容量:", cap(intChan)) num1 := <-intChan fmt.Println("取出來的第一個數(shù)據(jù)是:", num1) fmt.Println("取出之后的長度:", len(intChan), "取出之后的容量:", cap(intChan)) //在沒有使用協(xié)程的情況下,如果我們的管道數(shù)據(jù)已經(jīng)全部取出,再取就會報告deadlock } initChan的值為=0xc00007a080 initChan本身地址為0xc00000a028 長度: 2 容量: 3 取出來的第一個數(shù)據(jù)是: 1 取出之后的長度: 1 取出之后的容量: 3
要將什么樣的數(shù)據(jù)放到管道里面呢?就是這種數(shù)據(jù)是流動的,它一邊往里面放,另外一邊去讀取,這樣通信機制就形成了。<-ch這種接受方式也可以,將數(shù)據(jù)丟掉,數(shù)據(jù)不想要,這也是取的一種方式,只不過不想要。
channel 使用注意事項
(1)channel中只能存放指定的數(shù)據(jù)類型
(2)channle的數(shù)據(jù)放滿后,就不能再放入了(會出現(xiàn)死鎖的錯誤),如果從channel取出數(shù)據(jù)后,可以繼續(xù)放入
(3)在沒有使用協(xié)程的情況下,如果channel數(shù)據(jù)取完了,再取,就會報dead lock
讀寫channel案例
管道里面可以存放很多map,每個map里面又可以有多對的key/value。這里在使用map之前要先make一下 。
管道也是可以存放結構體實例的。
管道里面也可以存放指針。
如果希望在這個管道里面存放的是混合類型的數(shù)據(jù),我們既想放結構體又想放字符串。這里的數(shù)據(jù)類型為空接口類型interface{},因為任何的數(shù)據(jù)類型都認為實現(xiàn)了空接口。
注意:取出來的時候記得使用類型斷言。
package main import ( "fmt" "reflect" ) type Cat struct { Name string Age int } func main() { allChan := make(chan interface{}, 3) cat1 := Cat{ Name: "1", Age: 10, } allChan <- "hello" allChan <- 1 allChan <- cat1 <-allChan <-allChan newCat := <-allChan fmt.Println(reflect.TypeOf(newCat)) fmt.Printf("%T\n %#v\n", newCat, newCat) //fmt.Println(c.Name, c.Age) 這種寫法是錯誤的,編譯器通不過,使用類型斷言即可 c := newCat.(Cat) fmt.Println(c.Name, c.Age) }
6)存放函數(shù)
ch := make(chan func(string) string, 10) ch <- func(name string) string { //使用匿名函數(shù) return "hello " + name }
到此這篇關于Golang channle管道的基本使用及快速入門的文章就介紹到這了,更多相關Golang channle管道內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
GO使用socket和channel實現(xiàn)簡單控制臺聊天室
今天小編給大家分享一個簡單的聊天室功能,聊天室主要功能是用戶可以加入離開聊天室,實現(xiàn)思路也很簡單明了,下面小編給大家?guī)砹送暾a,感興趣的朋友跟隨小編一起看看吧2021-12-12Go語言同步與異步執(zhí)行多個任務封裝詳解(Runner和RunnerAsync)
這篇文章主要給大家介紹了關于Go語言同步與異步執(zhí)行多個任務封裝(Runner和RunnerAsync)的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。2018-01-01go語言通過odbc操作Access數(shù)據(jù)庫的方法
這篇文章主要介紹了go語言通過odbc操作Access數(shù)據(jù)庫的方法,實例分析了Go語言通過odbc連接、查詢與關閉access數(shù)據(jù)庫的技巧,需要的朋友可以參考下2015-03-03Go語言映射內(nèi)部實現(xiàn)及基礎功能實戰(zhàn)
這篇文章主要為大家介紹了Go語言映射的內(nèi)部實現(xiàn)和基礎功能實戰(zhàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪<BR>2022-03-03