Golang教程:goroutine協程

來源:互聯網
上載者:User

在上一篇中,我們討論了並發,以及並發和並行的區別。在這篇教程中我們將討論在Go中如何通過Go協程實現並發。

什麼是協程

Go協程(Goroutine)是與其他函數或方法同時啟動並執行函數或方法。可以認為Go協程是輕量級的線程。與建立線程相比,建立Go協程的成本很小。因此在Go中同時運行上千個協程是很常見的。

Go協程對比線程的優點

  • 與線程相比,Go協程的開銷非常小。Go協程的堆棧大小隻有幾kb,它可以根據應用程式的需要而增長和縮小,而線程必須指定堆棧的大小,並且堆棧的大小是固定的。
  • Go協程被多工到較少的OS線程。在一個程式中數千個Go協程可能只運行在一個線程中。如果該線程中的任何一個Go協程阻塞(比如等待使用者輸入),那麼Go會建立一個新的OS線程並將其餘的Go協程移動到這個新的OS線程。所有這些操作都是 runtime 來完成的,而我們程式員不必關心這些複雜的細節,只需要利用 Go 提供的簡潔的 API 來處理並發就可以了。
  • Go 協程之間通過通道(channel)進行通訊。通道可以防止多個協程訪問共用記憶體時發生竟險(race condition)。通道可以想象成多個協程之間通訊的管道。我們將在下一篇教程中介紹通道。

如何建立一個協程?

在函數或方法調用之前加上關鍵字 go,這樣便開啟了一個並發的Go協程。

讓我們建立一個協程:

package mainimport (      "fmt")func hello() {      fmt.Println("Hello world goroutine")}func main() {      go hello()    fmt.Println("main function")}

第11行,go hello() 開啟了一個新的協程。現在 hello() 函數將和 main() 函數一起運行。main 函數在單獨的協程中運行,這個協程稱為主協程。

運行這個程式,你將得到一個驚喜。

程式僅輸出了一行文本: main function。我們建立的協程發生了什嗎?我們需要瞭解Go協程的兩個屬性,以瞭解為什麼發生這種情況。

  • 當建立一個Go協程時,建立這個Go協程的語句立即返回。與函數不同,程式流程不會等待Go協程結束再繼續執行。程式流程在開啟Go協程後立即返回並開始執行下一行代碼,忽略Go協程的任何傳回值。
  • 在主協程存在時才能運行其他協程,主協程終止則程式終止,其他協程也將終止。

我想你已經知道了為什麼我們的協程為什麼沒有運行。在11行調用 go hello()後,程式的流程直接調轉到下一條語句執行,並沒有等待 hello 協程退出,然後列印 main function。接著主協程結束運行,不會再執行任何代碼,因此 hello 協程沒有得到啟動並執行機會。

讓我們修複這個問題:

package mainimport (      "fmt"    "time")func hello() {      fmt.Println("Hello world goroutine")}func main() {      go hello()    time.Sleep(1 * time.Second)    fmt.Println("main function")}

上面的程式中,第13行,我們調用 time 包的 Sleep 函數來使調用該函數所在的協程休眠。在這裡是讓主協程休眠1秒鐘。現在調用 go hello() 有了足夠的時間得以在主協程退出之前執行。該程式首先列印 Hello world goroutine,等待1秒鐘之後列印 main function

在主協程中使用 Sleep 函數等待其他協程結束的方法是不正規的,我們用在這裡只是為了說明Go協程是如何工作的。通道可以用於阻塞主協程,直到其他協程執行完畢。我們將在下一篇教程中討論通道。

開啟多個協程

讓我們寫一個程式開啟多個協程來更好的理解協程:

package mainimport (      "fmt"    "time")func numbers() {      for i := 1; i <= 5; i++ {        time.Sleep(250 * time.Millisecond)        fmt.Printf("%d ", i)    }}func alphabets() {      for i := 'a'; i <= 'e'; i++ {        time.Sleep(400 * time.Millisecond)        fmt.Printf("%c ", i)    }}func main() {      go numbers()    go alphabets()    time.Sleep(3000 * time.Millisecond)    fmt.Println("main terminated")}

上面的程式在第21和22行開啟了兩個協程。現在這兩個協程同時執行。numbers 協程最初睡眠 250 毫秒,然後列印 1,接著再次睡眠然後列印2,以此類推,直到列印到 5。類似地,alphabets 協程列印從 a 到 e 的字母,每個字母之間相隔 400 毫秒。主協程開啟 numbers 和 alphabets 協程,等待 3000 毫秒,最後終止。

程式的輸出為:

1 a 2 3 b 4 c 5 d e main terminated

下面的圖片描述了這個程式是如何工作的

中,藍色的線框表示 numbers 協程,栗色的線框表示 alphabets 協程。綠色的線框表示主協程。黑色的線框合并了上述三個協程,向我們展示了該程式的工作原理。每個框頂部的 0ms,250 ms 的字串表示以毫秒為單位的時間,在每個框底部的 1,2,3 表示輸出。 
藍色的線框告訴我們在 250ms 的時候列印了1,在 500ms 的時候列印了2,以此類推。因此最後一個線框底部的輸出:1 a 2 3 b 4 c 5 d e main terminated 也是整個程式的輸出。上面的映像是很好理解的,您將能夠瞭解該程式的工作原理。

 

 

 

本文轉自:https://blog.csdn.net/u011304970/article/details/75096323?locationNum=3&fps=1

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.