九、Golang并發和線程模型

      網友投稿 807 2025-04-02

      @Author:Runsen

      開始前來介紹幾個概念:

      進程:進程是程序在操作系統中的一次執行過程,系統進行資源分配和調度的一個獨立單位。

      線程:線程是進程的一個執行實體,是 CPU 調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位。

      并發:多線程程序在單核心的 cpu 上運行,稱為并發

      并行:多線程程序在多核心的 cpu 上運行,稱為并行。

      協程:獨立的棧空間,共享堆空間,調度由用戶自己控制,本質上有點類似于用戶級線程,一個線程上可以跑多個協程,協程是輕量級的線程。

      并發與并行并不相同,并發主要由切換時間片來實現“同時”運行,并行則是直接利用多核實現多線程的運行,Go程序可以設置使用核心數,以發揮多核計算機的能力。

      線程主要分為用戶線程和內核線程,用戶線程由各語言代碼所支持,而內核線程是由操作系統內核所支持。多線程模型主要就是用戶線程與內核線程的連接方式:

      下面我們來探討Go的線程模型,首先我們先來回顧下常見的三種線程模型,然后在介紹Go中獨特的線程模型CSP。

      文章目錄

      三種線程模型

      Goroutine

      CSP

      三種線程模型

      線程模型主要有三種:1、內核級別線程;2、用戶級別線程;3、混合線程,分別對應的是1:1、N:1、M:N。

      內核級別線程:一對一模型(1 : 1):每個用戶級線程映射到一個內核級線程。優點是緩存讀寫快速,缺點是容易阻塞。

      用戶級別線程: 多對一模型(M : 1):多個用戶級線程映射到一個內核級線程,線程管理在用戶空間完成。

      混合線程:多對多模型(M : N):內核線程和用戶線程的數量比為 M : N,綜合了前兩種的優點

      Goroutine

      goroutine 是 Go 語言并行設計的核心,有人稱之為 go 程。goroutine 是輕量級線程,goroutine 的調度是由 Golang 運行時進行管理的。在Java中,goroutine就是Thead 。

      goroutine 語法格式:go 函數名( 參數列表 )。例如:go f(x, y, z),開啟一個新的 goroutine:f(x, y, z)。

      并發編程中,我們通常想將一個過程切分成幾塊,然后讓每個 goroutine 各自負責一塊工作,當一個程序啟動時,主函數在一個單獨的 goroutine 中運行,我們叫它 `main goroutine。新的 goroutine 會用 go 語句來創建。而 go 語言的并發設計,讓我們很輕松就可以達成這一目的。

      我們來看一個示例。

      package main import ( "fmt" "time" ) func newTask() { i := 0 for { i++ fmt.Printf("new goroutine: i = %d\n", i) time.Sleep(1*time.Second) //延時1s } } func main() { //創建一個 goroutine,啟動另外一個任務 go newTask() i := 0 //main goroutine 循環打印 不會暫停 for { i++ fmt.Printf("main goroutine: i = %d\n", i) time.Sleep(1 * time.Second) //延時1s } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      程序運行結果:

      如果主 goroutine 退出后,那么其它的工作 goroutine 也會自動退出:

      package main import ( "fmt" "time" ) func newTask() { i := 0 for { i++ fmt.Printf("new goroutine: i = %d\n", i) time.Sleep(1 * time.Second) //延時1s } } func main() { //創建一個 goroutine,啟動另外一個任務 go newTask() fmt.Println("main goroutine exit") }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      程序運行結果如下,不會一直執行。

      new goroutine: i = 1 main goroutine exit

      1

      2

      上面就是Go實現了并發比較常見的Goroutine方法。

      CSP

      我們常見的多線程模型一般是通過共享內存實現的(就是Goroutine的原理),但是共享內存就會有很多問題。比如資源搶占的問題、一致性問題等等。為了解決這些問題,我們需要引入多線程鎖、原子操作等等限制來保證程序執行結果的正確性。

      這就引出了另外一種是Go語言特有的并發形式,也是Go語言推薦的:CSP(communicating sequential processes)并發模型。

      Go的CSP并發模型,是通過goroutine和channel來實現的。

      CSP模式中,消息是通過Channel來通訊的,Channel相當于一個消息通訊的中間人,這樣可以讓兩個通訊實體的耦合更松一些

      下面Runsen先介紹下Channel,回顧一下基礎知識。通道可用于兩個 goroutine 之間通過傳遞一個指定類型的值來同步運行和通訊。操作符 <-用于指定通道的方向,發送或接收。如果未指定方向,則為雙向通道。

      ch <- v // 把 v 發送到通道 ch v := <-ch // 從 ch 接收數據 // 并把值賦給 v

      1

      2

      3

      聲明一個通道很簡單,我們使用chan關鍵字即可,通道在使用前必須先創建:

      ch := make(chan int)

      1

      channel分為兩種,有緩沖channel和無緩沖channel,默認情況下,通道是不帶緩沖區的。我們通過下邊的代碼例子來區分不同的channel種類。

      package main import ( "fmt" ) func main() { pipline := make(chan string) //構造無緩沖通道 pipline <- "hello world" //發送數據 fmt.Println(<-pipline) //讀數據 }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      九、Golang并發和線程模型

      11

      運行會拋出錯誤,如下:

      fatal error: all goroutines are asleep - deadlock!

      1

      如果把這個例子改成有緩沖通道還會阻塞嗎?我們繼續看下邊的例子:

      package main import ( "fmt" ) func main() { pipline := make(chan string, 1 ) //構造無緩沖通道 pipline <- "hello world" //發送數據 fmt.Println(<-pipline) //讀數據 } hello world

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      這里運行正常,此時就說明了緩沖和沒有緩沖的區別在于在發送操作是否發生在有接受者時。那么,對于有緩沖通道會發生什么特殊情況呢?

      如果這段代碼,通道容量為 1,但是往通道中寫入兩條數據,對于一個協程來說就會造成死鎖。

      package main import ( "fmt" ) func main() { ch1 := make(chan string, 1) ch1 <- "hello world" ch1 <- "hello China" fmt.Println(<-ch1) } //fatal error: all goroutines are asleep - deadlock!

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      每個緩沖通道,都有容量,當通道里的數據量等于通道的容量后,此時再往通道里發送數據,就失造成阻塞,必須等到有人從通道中消費數據后,程序才會往下進行。

      下面,我們看goroutine和channel實現CSP并發模型,代碼來自菜鳥教程。

      package main import "fmt" // 計算數字之和 func sum(s []int, c chan int) { sum := 0 for _, v := range s { sum += v } c <- sum // 把 sum 發送到通道 c } func main() { s := []int{7, 2, 8, -9, 4, 0} c := make(chan int) go sum(s[:len(s)/2], c) //-9+4+0 go sum(s[len(s)/2:], c) // 7+2+8 x, y := <-c, <-c // 從通道 c 中接收 fmt.Println(x, y, x+y) //-5 17 12\ }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      上面示例通過兩個 goroutine 來計算數字之和,在 goroutine 完成計算后,它會計算兩個結果的和。這里的channel是沒有緩沖。

      通道可以設置緩沖區,通過 make 的第二個參數指定緩沖區大小。

      package main import "fmt" func sum(s []int, c chan int) { sum := 0 for _, v := range s { sum += v } c <- sum // 把 sum 發送到通道 c } func main() { // 這里我們定義了一個可以存儲整數類型的帶緩沖通道 // 緩沖區大小為2,因為存儲了一個數字,所以沒有報錯 s := []int{7, 2, 8, -9, 4, 0} c := make(chan int ,2) go sum(s[:len(s)/2], c) go sum(s[len(s)/2:], c) x, y := <-c, <-c // 從通道 c 中接收 fmt.Println(x, y, x+y) // -5 17 12 }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      Go 任務調度

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:項目管理關鍵點
      下一篇:查找兩列的數據,匹配不出來(兩列數據找出沒有的)
      相關文章
      亚洲国产精品久久久天堂| 国产亚洲一区二区三区在线| 午夜亚洲www湿好大| 久久久久亚洲av毛片大| 国产精品亚洲专区无码不卡| 精品久久久久久久久亚洲偷窥女厕| 亚洲伦理一二三四| 亚洲成人免费网址| 亚洲一区在线免费观看| 亚洲小说区图片区| 亚洲五月综合缴情婷婷| 亚洲一级毛片视频| 亚洲人成www在线播放| 亚洲精品天堂在线观看| 亚洲中文字幕久久精品无码VA| 亚洲18在线天美| 国产亚洲精aa在线看| 亚洲欧美日韩自偷自拍| 精品无码专区亚洲| ZZIJZZIJ亚洲日本少妇JIZJIZ| 国产亚洲精品成人a v小说| 亚洲伊人久久大香线蕉综合图片| 亚洲国产综合无码一区| 亚洲AV乱码久久精品蜜桃 | 久久亚洲春色中文字幕久久久 | 亚洲欧美中文日韩视频| 亚洲精品欧美综合四区| 青草久久精品亚洲综合专区| 亚洲国产成人五月综合网| 亚洲日本中文字幕一区二区三区| 国产亚洲情侣一区二区无| 亚洲成AV人片在| 亚洲视频免费一区| 91在线亚洲综合在线| 亚洲hairy多毛pics大全| 亚洲精品成人区在线观看| 亚洲精品无码成人AAA片| 亚洲尹人九九大色香蕉网站 | 亚洲国产精品成人综合色在线婷婷| 亚洲乱码在线播放| 亚洲成AV人影片在线观看|