Golang學習筆記:goroutine


1.goroutine

goroutine是go語言的並發體。在go語言里面能使用go關鍵字來實現並發。

go func()

1.1 概念介紹

goroutine本質上是協程,我剛剛學習的時候就粗略地認為goroutine是線程,直到最近才開始搞明白goroutine的基本概念。

並發

在很久以前,人們希望一個計算機(一個cpu)上能同時執行多項任務,讓cpu在某段時間內進行分片,在某段很短時間內執行程序a,然后又迅速得切換到程序b去執行,讓人們看起來就像是兩個程序在同時進行,這就是並發

進程

但是人們隨之發現,cpu在切換程序的時候,如果不保存上一個程序的狀態(也就是我們常說的context--上下文),直接切換下一個程序,就會丟失上一個程序的一系列狀態,於是引入了進程這個概念,用以划分好程序運行時所需要的資源。因此進程就是一個程序運行時候的所需要的基本資源單位(也可以說是程序運行的一個實體)。

並行

如果一個電腦有多個cpu,每個cpu都有進程在運行,這就是並行。

用戶態與內核態

為了防止用戶程序做出一些危險的指令,如關機,更改系統變量,修改別的進程數據,系統分為兩種運行狀態,用戶態以及內核態,用戶態是我們的程序所在的狀態,不能隨便對內核的底層進行操作。如果我們需要使用內核的底層操作的時候,內核提供了一種調用內核的接口,我們調用這些接口也就是系統調用,在進行系統調用的時候,cpu會切換到內核態,才能執行內核的函數。

線程

人們又發現一個問題,cpu切換多個進程的時候,會花費不少的時間,因為切換進程需要切換到內核態,而每次調度需要內核態都需要讀取用戶態的數據,進程一旦多起來,cpu調度會消耗一大堆資源,因此引入了線程的概念,線程本身幾乎不占有資源,他們共享進程里的資源,內核調度起來不會那么像進程切換那么耗費資源。

協程

但是線程還是需要內核去進行調度,切換起來也是需要把用戶態的數據寫入到內核態,也是需要耗費一定的計算機資源,那可以不可以將切換的調度改成我們自己控制的呢,答案是有的,協程就是把自己的調度算法交給程序(用戶態)去進行管理,能以更小的資源去進行並發。

goruntine

goroutine就是一個協程例子,可以根據自身調度器進行調度,當某個gooutine調用了time.sleep方法或者channel,mutex阻塞時候,調度器會使其入睡,喚醒另一個goroutine,根本不需要進入到內核態。

2.通信

goroutine本質上是協程,可以理解為不受內核調度,而受go調度器管理的線程。goroutine之間可以通過channel進行通信,如下:

func main() {
    c := make(chan string)
    go func(){
        c <- "hello"
    }()
    
    go func(){
       word := <- c + " world"
       fmt.Println(word)
    }()
    time.Sleep(1 * time.Second)
}

3.安全退出

goroutine只有在自身所在函數運行完畢,或者主函數運行完畢才會打斷,因而上面的例子需要等待一秒,不然未執行完的goroutine會直接被打斷。 如果我們並發的線程數量多了之后,我們不可能在main里面設置一個精確睡眠時間來評估所有的goroutine已經運行完畢然后退出。
這時候我們可以使用sync.WaitGroup來等待所有運行的goroutine運行結束后,再來退出main函數,主要原理是維護一個goroutine數量的計數器,每運行一個goroutine,計數器會加+1,運行結束后,計數器會-1,然后調用wait方法會一直阻塞,知道計數器為0,也就是當前運行的goroutine數量為0,實例如下:

func main() {
    var n sync.WaitGroup
    for i := 0; i < 20; i++ {
        n.Add(1)
        go func(i int, n *sync.WaitGroup) {
            defer n.Done()
            time.Sleep(1 * time.Second)
            fmt.Printf("goroutine %d is running\n", i)
        }(i, &n) 
    }   
    n.Wait()
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM