新聞中心
本節(jié)源碼位置 https://github.com/golang-minibear2333/golang/blob/master/4.concurrent/4.1-goroutine/”

以前我們寫并發(fā)的程序一般是用多線程來實現,自己維護一個線程池,在恰當的時候創(chuàng)建、銷毀、分配資源。
go 在并發(fā)方面為我們提供了一個語言級別的支持, goroutine 和 chan 相互配合,這決定了他的先天優(yōu)勢。
goroutine 的概念類似于線程, Go 程序運行時會自動調度和管理,系統(tǒng)能智能地將 goroutine 中的任務合理地分配給 CPU , 讓這些任務盡量并發(fā)運作。
他和線程對比
從使用上講
- 比線程更輕量級,可以創(chuàng)建十萬、百萬不用擔心資源問題。
- 和 chan 搭配使用,實現高并發(fā), goroutine 之間傳輸數據更方便。
- 如果訪問同一個數據塊,要小心數據競態(tài)問題、共享鎖還是互斥鎖的選擇問題、并發(fā)操作的數據同步問題(后面會說)
從其實現上講
- 從資源上講,線程的棧內存大小一般是固定的一般為 2MB ,雖然這個數值可以設置,但是 太大了浪費,太小了容易不夠用, 而 goroutine 棧內存是可變的,初始一般為 2KB ,隨著需求可以擴大達到 1GB。所以 goroutine 十分的輕量級,且能滿足不同的需求。
- 從調度上講,線程的調度由 OS 的內核完成;線程的切換需要 CPU 寄存器 和 內存的數據交換 ,從而切換不同的線程上下文。其觸發(fā)方式為 CPU時鐘 , 而 goroutine 的調度則比較輕量級,由自身的調度器完成。
- 協(xié)程同線程的關系,有些類似于 線程同進程的關系。
創(chuàng)建與使用
創(chuàng)建一個 goroutine ,只需要在函數前加一個 go 關鍵字就成了。
- go 函數名(參數)
看一個 dome
- func quickFun(){
- fmt.Println("maybe you can's see me!")
- }
- func main(){
- go quickFun() // 創(chuàng)建了一個 goroutine
- fmt.Println("hey")
- time.Sleep(time.Second)
- }
- goroutine 和 main 主線程同時運行
- main 運行結束會暴力終止所有協(xié)程,所以上面的程序多等待了 1 秒
- Go 程序從 main 包的 main() 函數開始,在程序啟動時, Go 程序就會為 main() 函數創(chuàng)建一個默認的 goroutine 。
輸出
- hey
- maybe you can's see me!
對,就是這么簡單,如果你的函數只在這里使用,也可以用匿名函數來創(chuàng)建 goroutine 。
- func main(){
- go func() {
- fmt.Println("hello ")
- }()
- time.Sleep(time.Second) //main運行結束會暴力終止所有協(xié)程,所以這里先等待1秒
- }
PS: 和線程不同,goroutine沒有唯一的id,所以我們沒辦法專門q針對某個協(xié)程進行操作。
goroutine
goroutine 是 Go 語言并行設計的核心。goroutine 是一種比線程更輕量的實現,十幾個 goroutine 可能在底層就是幾個線程。實際上是 Go 在 runtime、系統(tǒng)調用等多方面對 goroutine 調度進行了封裝和處理。
使用 goroutine 只需要簡單的在需要執(zhí)行的函數前添加 go 關鍵字即可。當執(zhí)行 goroutine 時候,Go 語言立即返回,接著執(zhí)行剩余的代碼,不會阻塞主線程。
下面我們通過一小段代碼來講解 go 的使用:
- //首先我們先實現一個 Add()函數
- func Add(a, b int) {
- c := a + b
- fmt.Println(c)
- }
- go Add(1, 2) //使用go關鍵字讓函數并發(fā)執(zhí)行
Go 的并發(fā)執(zhí)行就是這么簡單,當在一個函數前加上 go 關鍵字,該函數就會在一個新的 goroutine 中并發(fā)執(zhí)行,當該函數執(zhí)行完畢時,這個新的 goroutine 也就結束了。不過需要注意的是,如果該函數具有返回值,那么返回值會被丟棄。所以什么時候用 go 還需要酌情考慮。
接著我們通過一個案例來體驗一下 Go 的并發(fā)到底是怎么樣的。新建源文件 goroutine2.go,輸入以下代碼:
- package main
- import "fmt"
- func Add(a, b int) {
- c := a + b
- fmt.Println(c)
- }
- func main() {
- for i := 0; i < 10; i++ {
- go Add(i, i)
- }
- }
執(zhí)行 goroutine.go 文件會發(fā)現屏幕上什么都沒有,但程序并不會報錯,這是什么原因呢?
原來當主程序執(zhí)行到 for 循環(huán)時啟動了 10 個 goroutine,然后主程序就退出了,而啟動的 10 個 goroutine 還沒來得及執(zhí)行 Add() 函數,所以程序不會有任何輸出。也就是說主 goroutine 并不會等待其他 goroutine 執(zhí)行結束。
Go 語言提供的信道(channel)就是專門解決并發(fā)通信問題的,下一節(jié)我們將詳細介紹。
小結
學 go 語言必學并發(fā),通過本節(jié)我們知道了協(xié)程是非常容易創(chuàng)建的,而且他非常輕量只占用 4k,其他語言很容易就上MB
協(xié)程的使用還要配合數據傳輸,生產者消費者模型,關于協(xié)程的調度,我們后續(xù)再說。
另外并發(fā) bug 的定位和解決是老大難的問題了,平時就要注意的良好的代碼風格和編程習慣。
本文轉載自微信公眾號「機智的程序員小熊」,可以通過以下二維碼關注。轉載本文請聯系機智的程序員小熊公眾號。
本文名稱:Go語言中的并發(fā)特性
URL網址:http://www.dlmjj.cn/article/ccoehpc.html


咨詢
建站咨詢
