Go 併發編程-goroutine 初體驗

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"說到 Go 語言,被人討論最多的就是 Go 很擅長做高併發,並且不需要依賴外部的庫,語言本身就支持高併發。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Go 中實現這一能力的祕密是 goroutine,也經常被稱之爲協程,goroutine 是 Go 對協程的實現。在這篇文章中,會介紹協程的基本概念,以及 goroutine 的基本使用。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"1.什麼是協程","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"協程(Coroutine),又被稱之爲微線程,這個概念出現的時間很早,在 1963 年就有相關的文獻發表,但協程真正被用起來的時間很短。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於操作系統來說,線程是最小的調度單位,但對於一些高併發的環境,線程處理起來就比較喫力,一方面操作系統能夠分配的線程數量有限,另外線程之間的切換相對來說也比較大。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所以對於 Java 這類以線程爲調度單位的語言,一般會依靠外部的類庫來做到高併發,比如 Java 的Netty 就是一個開始高併發應用必不可少的庫。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"協程和線程非常類似,只是比線程更加輕量級,具體表現在協程之間的切換不需要涉及系統調用,也不需要互斥鎖或者信號量等同步手段,甚至都不需要操作系統的支持。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"協程與線程的行爲基本一致,但是協程是在語言層面實現的,而線程是操作系統實現的。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"2. Go 語言的協程","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 Go 語言中,支持兩種併發編程的模式,一種就是以 goroutine 和 channel 爲主,這種方式稱之爲 CSP 模式,這種方式的核心是在 goroutine 之間傳遞值來來實現併發。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"還有一種方式是傳統的共享內存式的模式,通過一些同步機制,比如鎖之類的機制來實現併發。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Go 程序通過 main 函數來啓動,main 函數啓動的時候也會啓動一個 goroutine,稱之爲","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"主 goroutine","attrs":{}},{"type":"text","text":"。然後在主 goroutine 中通過 go 關鍵字創建新的 goroutine。go 語句是立馬返回的,不會阻塞當前的 goroutine。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一個 Go 程序中可以創建的 goroutine 數量可以比線程數量多很多,這也是 Go 程序可以做到高併發的原因,goroutine 的實現原理,我們後續的文章再詳細聊,下面來看看看 goroutine 的使用。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"3. goroutine 的基本使用","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"goroutine 的使用很簡單,只需要在調用的函數前面添加 go 關鍵字,就會創建一個新的 goroutine:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"go"},"content":[{"type":"text","text":"func goroutine1() {\n fmt.Println(\"Hello goroutine\")\n}\n\nfunc main() {\n go goroutine1()\n fmt.Println(\"Hello main\")\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但運行上面的代碼之後,輸出的結果爲:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"Hello main\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"預想中的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Hello goroutine","attrs":{}}],"attrs":{}},{"type":"text","text":" 並沒有出現,因爲 main 方法執行完成之後,main 方法 所在的 goroutine 就銷燬了,其他的 goroutine 都沒有機會執行完。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以通過設置一個休眠時間來阻止主 goroutine 執行完成。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"go"},"content":[{"type":"text","text":"func goroutine1() {\n fmt.Println(\"Hello goroutine\")\n}\n\nfunc main() {\n go goroutine1()\n time.Sleep(1 * time.Second)\n fmt.Println(\"Hello main\")\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這樣,輸出結果就和我們預想的一樣了:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"Hello goroutine\nHello main\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但是這種方法也存在一些問題,這個休眠時間不太好設置,設置的過長,會浪費時間,設置的過短, goroutine 還沒運行完成,所以最好的方式是讓 goroutine 自己來決定。我們再改動一下代碼:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"go"},"content":[{"type":"text","text":"func goroutine2(isDone chan bool) {\n fmt.Println(\"child goroutine begin...\")\n time.Sleep(2 * time.Second)\n fmt.Println(\"child goroutine end...\")\n isDone
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章