Go 系列教程 —— 21. Go 協程

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。歡迎來到 [Golang 系列教程](https://studygolang.com/subject/2)的第 21 篇。 在前面的教程裡,我們探討了並發,以及並發與並行的區別。本教程則會介紹在 Go 語言裡,如何使用 Go 協程(Goroutine)來實現並發。## Go 協程是什嗎?Go 協程是與其他函數或方法一起並發啟動並執行函數或方法。Go 協程可以看作是輕量級線程。與線程相比,建立一個 Go 協程的成本很小。因此在 Go 應用中,常常會看到有數以千計的 Go 協程並發地運行。 ## Go 協程相比於線程的優勢- 相比線程而言,Go 協程的成本極低。堆棧大小隻有若干 kb,並且可以根據應用的需求進行增減。而線程必須指定堆棧的大小,其堆棧是固定不變的。- Go 協程會複用(Multiplex)數量更少的 OS 線程。即使程式有數以千計的 Go 協程,也可能只有一個線程。如果該線程中的某一 Go 協程發生了阻塞(比如說等待使用者輸入),那麼系統會再建立一個 OS 線程,並把其餘 Go 協程都移動到這個新的 OS 線程。所有這一切都在運行時進行,作為程式員,我們沒有直接面臨這些複雜的細節,而是有一個簡潔的 API 來處理並發。 - Go 協程使用通道(Channel)來進行通訊。通道用於防止多個協程訪問共用記憶體時發生競態條件(Race Condition)。通道可以看作是 Go 協程之間通訊的管道。我們會在下一教程詳細討論通道。 ## 如何啟動一個 Go 協程?調用函數或者方法時,在前面加上關鍵字 `go`,可以讓一個新的 Go 協程並發地運行。讓我們建立一個 Go 協程吧。```gopackage mainimport ("fmt")func hello() {fmt.Println("Hello world goroutine")}func main() {go hello()fmt.Println("main function")}```[線上運行程式](https://play.golang.org/p/zC78_fc1Hn)在第 11 行,`go hello()` 啟動了一個新的 Go 協程。現在 `hello()` 函數與 `main()` 函數會並發地執行。主函數會運行在一個特有的 Go 協程上,它稱為 Go 主協程(Main Goroutine)。**運行一下程式,你會很驚訝!**該程式只會輸出文本 `main function`。我們啟動的 Go 協程究竟出現了什麼問題?要理解這一切,我們需要理解兩個 Go 協程的主要性質。 - **啟動一個新的協程時,協程的調用會立即返回。與函數不同,程式控制不會去等待 Go 協程執行完畢。在調用 Go 協程之後,程式控制會立即返回到代碼的下一行,忽略該協程的任何傳回值。** - **如果希望運行其他 Go 協程,Go 主協程必須繼續運行著。如果 Go 主協程終止,則程式終止,於是其他 Go 協程也不會繼續運行。** 現在你應該能夠理解,為何我們的 Go 協程沒有運行了吧。在第 11 行調用了 `go hello()` 之後,程式控制沒有等待 `hello` 協程結束,立即返回到了代碼下一行,列印 `main function`。接著由於沒有其他可執行檔代碼,Go 主協程終止,於是 `hello` 協程就沒有機會運行了。我們現在修複這個問題。```gopackage mainimport ( "fmt""time")func hello() { fmt.Println("Hello world goroutine")}func main() { go hello()time.Sleep(1 * time.Second)fmt.Println("main function")}```[線上運行程式](https://play.golang.org/p/U9ZZuSql8-) 在上面程式的第 13 行,我們調用了 time 包裡的函數 [`Sleep`](https://golang.org/pkg/time/#Sleep),該函數會休眠執行它的 Go 協程。在這裡,我們使 Go 主協程休眠了 1 秒。因此在主協程終止之前,調用 `go hello()` 就有足夠的時間來執行了。該程式首先列印 `Hello world goroutine`,等待 1 秒鐘之後,接著列印 `main function`。 在 Go 主協程中使用休眠,以便等待其他協程執行完畢,這種方法只是用於理解 Go 協程如何工作的技巧。通道可用於在其他協程結束執行之前,阻塞 Go 主協程。我們會在下一教程中討論通道。 ## 啟動多個 Go 協程為了更好地理解 Go 協程,我們再編寫一個程式,啟動多個 Go 協程。 ```gopackage 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")}```[線上運行程式](https://play.golang.org/p/U9ZZuSql8-) 在上面程式中的第 21 行和第 22 行,啟動了兩個 Go 協程。現在,這兩個協程並發地運行。`numbers` 協程首先休眠 250 微秒,接著列印 `1`,然後再次休眠,列印 `2`,依此類推,一直到列印 `5` 結束。`alphabete` 協程同樣列印從 `a` 到 `e` 的字母,並且每次有 400 微秒的休眠時間。 Go 主協程啟動了 `numbers` 和 `alphabete` 兩個 Go 協程,休眠了 3000 微秒後終止程式。 該程式會輸出: ```1 a 2 3 b 4 c 5 d e main terminated ```程式的運作如所示。為了更好地觀看圖片,請在新標籤頁中開啟。 ![image](https://raw.githubusercontent.com/studygolang/gctt-images/master/golang-series/Goroutines-explained.png)第一張藍色的圖表示 `numbers` 協程,第二張褐紅色的圖表示 `alphabets` 協程,第三張綠色的圖表示 Go 主協程,而最後一張黑色的圖把以上三種協程合并了,表明程式是如何啟動並執行。在每個方框頂部,諸如 `0 ms` 和 `250 ms` 這樣的字串表示時間(以微秒為單位)。在每個方框的底部,`1`、`2`、`3` 等表示輸出。藍色方框表示:`250 ms` 列印出 `1`,`500 ms` 列印出 `2`,依此類推。最後黑色方框的底部的值會是 `1 a 2 3 b 4 c 5 d e main terminated`,這同樣也是整個程式的輸出。以片非常直觀,你可以用它來理解程式是如何運作的。 Go 協程的介紹到此結束。祝你愉快。**上一教程 - [並發入門](https://studygolang.com/articles/12341)****下一教程 - [通道](https://studygolang.com/articles/12402)**

via: https://golangbot.com/goroutines/

作者:Nick Coghlan 譯者:Noluye 校對:polaris1119

本文由 GCTT 原創編譯,Go語言中文網 榮譽推出

本文由 GCTT 原創翻譯,Go語言中文網 首發。也想加入譯者行列,為開源做一些自己的貢獻嗎?歡迎加入 GCTT!
翻譯工作和譯文發表僅用於學習和交流目的,翻譯工作遵照 CC-BY-NC-SA 協議規定,如果我們的工作有侵犯到您的權益,請及時聯絡我們。
歡迎遵照 CC-BY-NC-SA 協議規定 轉載,敬請在本文中標註並保留原文/譯文連結和作者/譯者等資訊。
文章僅代表作者的知識和看法,如有不同觀點,請樓下排隊吐槽

3359 次點擊  

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.