這是『就要學習 Go 語言』系列的第 21 篇分享文章markdown
提到併發,相信你們還聽過另外一個概念 -- 並行。我先給你們介紹下這二者之間的區別,再來說 Go 語言的併發。多線程
並行其實很好理解,就是同時執行的意思,在某一時間點可以執行多個任務。 想達到並行效果,最簡單的方式就是藉助多線程或多進程,這樣纔可在同一時刻執行多個任務。單線程是永遠沒法達到並行狀態的。 併發是在某一時間段內能夠同時處理多個任務。咱們一般會說程序是併發設計的,也就是說它容許多個任務同時執行,這個同時指的就是一段時間內。單線程中多個任務以間隔執行實現併發。 能夠說,多線程或多進程是並行的基礎,但單線程也經過協程實現了併發。併發
舉個常見的例子,一臺單核電腦能夠下載、聽音樂,實際上這兩個任務是這樣執行的,只不過這兩個任務切換時間短,給人的感受是同時執行的。 函數
一臺多核電腦的任務執行就是像下面這種圖顯示的同樣: 能夠看到,同一時刻能執行多個任務。這種任務執行方式纔是真正的並行。Go 經過協程實現併發,協程之間靠信道通訊,本篇文章先給你們介紹協程的使用,後面再寫信道。oop
協程(Goroutine)能夠理解成輕量級的線程,但與線程相比,它的開銷很是小。所以,Go 應用程序一般能併發地運行成千上萬的協程。 Go 建立一個協程很是簡單,只要在方法或函數調用以前加關鍵字 go 便可。學習
func printHello() { fmt.Println("hello world goroutine") } func main() { go printHello() // 建立了協程 fmt.Println("main goroutine") } 複製代碼
輸出:spa
main goroutine
複製代碼
上面代碼,第 6 行使用 go 關鍵字建立了協程,如今有兩個協程,新建立的協程和主協程。printHello() 函數將會獨立於主協程併發地執行。 是的,你沒有看錯,程序的輸出就是這樣,不信?你能夠實際運行下程序。你驚訝的是,printHello() 函數爲何沒有輸出,到底發生了什麼? 當協程建立完畢以後,主函數當即返回繼續執行下一行代碼,不像函數調用,須要等函數執行完成。主協程執行完畢,程序便退出,printHello 協程隨即也退出,便不會有輸出。.net
修改下代碼:線程
func printHello() { fmt.Println("hello world goroutine") } func main() { go printHello() time.Sleep(1*time.Second) fmt.Println("main goroutine") } 複製代碼
協程建立完成以後,main 協程先休眠 1s,預留給 printHello 協程執行的時間,因此此次輸出:設計
hello world goroutine
main goroutine
複製代碼
上一節就提到,能夠建立多個協程,來看下例子:
func printNum() { for i := 1; i <= 5; i++ { time.Sleep(20 * time.Millisecond) fmt.Printf("%d ", i) } } func printChacter() { for i := 'a'; i <= 'e'; i++ { time.Sleep(40 * time.Millisecond) fmt.Printf("%c ", i) } } func main() { go printNum() go printChacter() time.Sleep(3*time.Second) fmt.Println("main terminated") } 複製代碼
上面的代碼,除主協程以外,新建立了兩個協程:printNum 協程和 printChacter 協程。printNum 協程每隔 20 毫秒輸出 5 個數,printChacter 協程每隔 40 毫秒輸出字母。主協程建立完這兩個協程以後休眠 1s,等待其餘協程執行完成。 程序輸出(你的輸出可能跟個人不同):
1 a 2 3 b 4 5 c d e main terminated 複製代碼
話說回來,經過加 time.Sleep() 函數等待協程執行完成是一種「黑科技」。在實際生產環境中,無論咱們是否知道其餘協程執行完成須要多少時間,都不能在主協程中添加隨機睡眠調用等待其餘協程執行完成。那怎麼辦?Go 給咱們提供了信道,當協程執行完畢,可以通知到主協程,還可以實現協程間通訊。下節課咱們來討論一下。
在函數那篇文章講過,存在匿名函數,經過關鍵字 go 調用匿名函數就是匿名協程。咱們修改以前的例子:
func main() { go func() { fmt.Println("hello world goroutine") }() time.Sleep(1*time.Second) fmt.Println("main goroutine") } 複製代碼
輸出結果跟以前的同樣。
但願這篇文章給你帶來收穫,Good Day !
原創文章,若需轉載請註明出處!
歡迎掃碼關注公衆號「Golang來啦」或者移步 seekload.net ,查看更多精彩文章。
給你準備了學習 Go 語言相關書籍,公號後臺回覆【電子書】領取!