Go語言中goroutine的使用
一、什么是 Goroutine ?
在java/c++中我們要實現(xiàn)并發(fā)編程的時候,我們通常需要自己維護一個線程池,并且需要自己去包裝一個又一個的任務,同時需要自己去調(diào)度線程執(zhí)行任務并維護上下文切換,這一切通常會耗費程序員大量的心智。那么能不能有一種機制,程序員只需要定義很多個任務,讓系統(tǒng)去幫助我們把這些任務分配到CPU上實現(xiàn)并發(fā)執(zhí)行呢?
Go語言中的goroutine就是這樣一種機制,goroutine的概念類似于線程,但 goroutine是由Go的運行時(runtime)調(diào)度和管理的。Go程序會智能地將 goroutine 中的任務合理地分配給每個CPU。Go語言之所以被稱為現(xiàn)代化的編程語言,就是因為它在語言層面已經(jīng)內(nèi)置了調(diào)度和上下文切換的機制。
在Go語言編程中你不需要去自己寫進程、線程、協(xié)程,你的技能包里只有一個技能–goroutine,當你需要讓某個任務并發(fā)執(zhí)行的時候,你只需要把這個任務包裝成一個函數(shù),開啟一個goroutine去執(zhí)行這個函數(shù)就可以了,就是這么簡單粗暴。
二、使用 Goroutine
Go語言中使用goroutine非常簡單,只需要在調(diào)用函數(shù)的時候在前面加上go關鍵字,就可以為一個函數(shù)創(chuàng)建一個goroutine。
一個goroutine必定對應一個函數(shù),可以創(chuàng)建多個goroutine去執(zhí)行相同的函數(shù)。
單個 goroutine
package main
import "fmt"
func hello() {
fmt.Println("Hello Goroutine!")
}
func main() {
go hello()
fmt.Println("main goroutine done!")
}執(zhí)行這段程序:
main goroutine done!
那么問題來了:為什么 Hello Goroutine! 沒有輸出呢?
在程序啟動時,Go程序就會為main()函數(shù)創(chuàng)建一個默認的goroutine。
當main()函數(shù)返回的時候該goroutine就結(jié)束了,所以在main()函數(shù)中啟動的goroutine會一同結(jié)束,main函數(shù)所在的goroutine就像是權(quán)利的游戲中的夜王,其他的goroutine都是異鬼,夜王一死它轉(zhuǎn)化的那些異鬼也就全部GG了。
所以咱們要想辦法讓main函數(shù)等一等hello函數(shù),最簡單粗暴的方式就是time.Sleep了。
示例:
package main
import "fmt"
func hello() {
fmt.Println("Hello Goroutine!")
}
func main() {
go hello()
fmt.Println("main goroutine done!")
time.Sleep(time.Second) // 等待1秒
}執(zhí)行這段程序:
Hello Goroutine!
main goroutine done!
多個 goroutine
package main
import "fmt"
func hello() {
fmt.Println("Hello Goroutine!")
}
func word() {
fmt.Println("Word Goroutine!")
}
func main() {
go hello()
go word()
fmt.Println("main goroutine done!")
time.Sleep(2 * time.Second) // 等待2秒
}執(zhí)行這段程序:
Hello Goroutine!
Word Goroutine!
main goroutine done!
開啟多個 goroutine 只需要再使用一次go關鍵字就可以了。
同樣的,咱們?yōu)榱俗屗軌蛲暾敵?,使?time.Sleep 讓main函數(shù)等待 goroutine 執(zhí)行完成。
sync.WaitGroup 的使用
上面咱們講了如何開啟goroutine,為了goroutine正常輸出,增加了 time.Sleep 等待。
但在我們實際項目開發(fā)中,生硬的使用time.Sleep肯定是不合適的。那我們應該如何才能正確優(yōu)雅的讓 main 函數(shù)等待 goroutine 執(zhí)行完之后再執(zhí)行呢?
go語言提供了一個 sync.WaitGroup 的一個計數(shù)器的功能??梢杂脕韮?yōu)雅的實現(xiàn) goroutine 的正常執(zhí)行和 main 函數(shù)的等待。
示例:
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
func hello(){
defer wg.done() // 計數(shù)器 - 1
fmt.Println("Hello Goroutine!")
}
func main(){
wg.Add(1) // 計數(shù)器 + 1
go hello()
wg.wait() // 阻塞直到計數(shù)器變?yōu)?
fmt.Println("main goroutine done!")
}執(zhí)行這段程序:
Hello Goroutine!
main goroutine done!
| 方法名 | 功能 |
|---|---|
| (wg * WaitGroup) Add(delta int) | 計數(shù)器+delta |
| (wg *WaitGroup) Done() | 計數(shù)器-1 |
| (wg *WaitGroup) Wait() | 阻塞直到計數(shù)器變?yōu)? |
sync.WaitGroup內(nèi)部維護著一個計數(shù)器,計數(shù)器的值可以增加和減少。例如當我們啟動了 N 個并發(fā)任務時,就將計數(shù)器值增加N。每個任務完成時通過調(diào)用Done()方法將計數(shù)器減1。通過調(diào)用Wait()來等待并發(fā)任務執(zhí)行完,當計數(shù)器值為0時,表示所有并發(fā)任務已經(jīng)完成。
在實際項目中使用sync.WaitGroup 可以更好的、更優(yōu)雅的控制goroutine。
三. 結(jié)束語
到此這篇關于Go語言中goroutine的使用的文章就介紹到這了,更多相關Go語言goroutine內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
go實現(xiàn)thrift的網(wǎng)絡傳輸性能及需要注意問題示例解析
這篇文章主要為大家介紹了go實現(xiàn)thrift的網(wǎng)絡傳輸性能及需要注意問題示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-09-09

