二一:GO語言的goroutine(協程)和channel(管道),重點!!!

前言:要了解協程和管道首先得了解以下四個概念

  進程和線程簡單說明

  1.進程就是程序在操作系統中的一次執行過程,是系統進行資源分配和調度的基本單位

  2.線程是進程的一個執行實例,是程序執行的最小單元,它是比進程更小的獨立運行的基本單位

  3.一個進程可以創建銷燬多個線程,同一個進程的多個線程可以併發執行

  4.一個程序至少有一個進程,一個進程至少有一個線程

個人理解:把計算機比作一家公司,程序就是這家公司的部門,進程就是公司安排的某個工作內容的完成過程,線程就是部門裏處理這個工作內容的人去完成的實例,公司下發工作內容就相當於給部門下發任務,由公司(這裏公司就是隻CPU,後面會跟併發和並行有關聯)來調動相應的人數去處理這個或者這些任務,如有錯誤請指出,謝謝。

  併發和並行

  1.多線程程序在單核上運行,就是併發

  2.多線程程序在多核上運行,就是並行

個人理解:沿用上一個例子,併發就是有多個任務安排,但是現在部門內部只有一個人,這個人就得同時處理所有工作內容,感覺上是所有的任務都在同時處理,但實際上在一個時間點上,這個人只能處理一個問題,只是在不停地切換不同的任務處理,而非處理完成一個任務後再切換到下一個任務。並行就是部門內部有多個人,可以同時處理多個任務

  

GO的協程和主線程

  1.GO主線程(有程序員直接稱爲線程/也可以理解成進程),一個GO線程上,可以起多個協程,可以這樣理解,協程是輕量級的線程(編譯器做優化)。

  2.GO協程的特點

  • 有獨立的棧空間
  • 有共享程序堆空間
  • 調度由用戶控制
  • 協程是輕量級的線程

goroutine 快速入門小結

  1.主線程是一個物理線程嗎,直接作用在cpu上的,是重量級的,非常消耗cpu資源。

  2.協程從主線程開啓的,是輕量級的線程,是邏輯態的。對資源消耗相對小。

  3.Golang的協程機制是重要的特點,可以輕鬆的開啓上萬個協程。其他編程語言的併發機制是一般基於線程的,開啓過多的線程,資源消耗大,這就突顯了Golang在併發上的優勢

goroutine的調度模型(MPG模式)

  基本介紹

  M:操作系統的主線程(是物理線程)

  P:協程執行需要的上下文

  G:協程

簡單來說,就是一個協程阻塞了,會把後續操作自動放到其餘空閒的協程中執行,等到阻塞協程完成後,會把剩餘的任務又使用該線程繼續執行。這樣來回切換可以保證阻塞的協程不會影響效率。達成併發/並行的效果

內容較多,需詳細瞭解請自行搜索查詢。

Channel(管道)

  在協程中進行相互通信時(都要使用同一個全局變量)會產生資源競爭(同時對某一個全局變量進行讀寫)的問題。

  channel用於解決不同的goroutine之間通信的問題,也可以使用加互斥鎖的方式來達成這個目的。但互斥鎖沒這玩意兒好。

  基本介紹

    1.channel本質就是一個數據結構-隊列

    2.數據是先進先出,與棧是相反的,棧是先進後出

    3.線程安全,多個goroutine訪問時,不需要加鎖,本身就是線程安全的

    4.channel是有類型的,一個string的channel只能存放string類型的數據

  定義/聲明

    var 變量名 chan 數據類型

  舉例:

    var intChan chan int

    var stringChan chan string

    var structChan chan Struct (結構體)

    var mapChan chan map[string]int (map)

  channel是一個引用類型,必須初始化才能寫入數據,即使用make進行初始化,第二個參數爲channel的長度

  int類型的管道只能存放int類型的數據

  

 

 

  給管道寫入數據,拿上面的intChan舉例

    

 

   讀取管道中的數據

    

 

  channel的遍歷

    channel支持for-range的方式進行遍歷,但注意兩個細節

      1.在遍歷時,如果chanel沒有關閉,則會出現deadlock的錯誤

      2.在遍歷時,如果channel已經關閉,則會正常遍歷數據,遍歷完後,就會退出遍歷

 

channel和goroutine使用的注意事項

    1.channel總只能存放指定的數據類型

    2.channel的數據放滿後就不能再放入

    3.如果從channel取出數據後,可以繼續放入

    4.在沒有使用協程的情況下,如果channel的數據取完了,再取就會報dead lock,channel在取值時,實際上會返回兩個值,x,ok:=<-chan,第二個值爲ok,在成功取出,爲false則失敗

    5.使用內置函數close可以關閉channel,當channel關閉後,就不能再向channel寫數據了,但是仍然可以從該channel讀取數據。

    6.在默認情況下,channel管道是雙向的,即可度又可寫

      var chan2 chan <- int   //只可寫入的int型管道

      var chan2 <-chan int    //只可讀取的int型管道

    7.使用select可以解決從channel管道中讀取數據的阻塞問題

    8.groutine中使用recover,解決協程中出現的panic,防止程序出現崩潰

 

  

  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章