一篇文章帶你入門(mén)Go語(yǔ)言基礎(chǔ)之并發(fā)
回復(fù)“Go語(yǔ)言”即可獲贈(zèng)從入門(mén)到進(jìn)階共10本電子書(shū)
含光混世貴無(wú)名,何用孤高比云月?
前言
Hey,大家好,我是碼農(nóng)星期八,終于到了Go中最牛掰的地方,并發(fā),這也是Go為什么能快速火的原因。
部署方便,不需要容器,隨便跑一個(gè)都是相當(dāng)于Nginx的存在,怎么肯能不火
所以,來(lái)看看扒!!!
引言
Go語(yǔ)言,專(zhuān)門(mén)為并發(fā)而生的語(yǔ)言,每啟動(dòng)一個(gè)微線(xiàn)程創(chuàng)建一個(gè)代價(jià)大概2KB起步
假設(shè)一個(gè)內(nèi)存條大小4G,一個(gè)微線(xiàn)程2kb,1G=1024M=1048576kb,1048576/2=524288,五十多萬(wàn)個(gè)
但是你知道像Java,Python等語(yǔ)言,一個(gè)線(xiàn)程代價(jià)多大嗎???,2MB起步,代價(jià)直接翻了千倍
所以,激動(dòng)吧,隨便用Go寫(xiě)一個(gè)web程序,基本都相當(dāng)于Nginx
goroutine
Go中的微線(xiàn)程,也叫做goroutine,goroutine是并行處理任務(wù)的
就像我用兩只手同時(shí)操作兩個(gè)手機(jī)打游戲一樣
而不是一個(gè)手玩玩這個(gè),一個(gè)手玩玩那個(gè),這樣切換式玩法
goroutine由Go的runtime完成調(diào)度,goroutine的本質(zhì)是在代碼(用戶(hù)態(tài))級(jí)別完成的切換,代價(jià)很小
像Java,Python等語(yǔ)言的線(xiàn)程,是在操作系統(tǒng)(內(nèi)核態(tài))級(jí)別完成的切花,所以代價(jià)非常大
由于goroutine是由runtime完成切換,并且runtime經(jīng)過(guò)Google公司的數(shù)位大佬優(yōu)化,已經(jīng)很小母牛上山了,牛逼哄哄了。
使用goroutine
在Go中使用goroutine很簡(jiǎn)單,只需要在想調(diào)用的函數(shù)前加一個(gè)go就行了,這就代表啟動(dòng)了一個(gè)goroutine
普通調(diào)用函數(shù)方式
函數(shù)
func Say() {time.Sleep(time.Second)fmt.Println("我在說(shuō)話(huà)說(shuō)了1s說(shuō)完了...")}
main
func main() {//開(kāi)始時(shí)間var start_time = time.Now()//啟動(dòng)10個(gè)say說(shuō)話(huà)for i := 0; i < 10; i++ {Say()}//結(jié)束時(shí)間var end_time = time.Now()//計(jì)算時(shí)間差fmt.Println(end_time.Sub(start_time))}
執(zhí)行結(jié)果

循環(huán)了10次,耗時(shí)10s,有點(diǎn)慢啊!
goroutine調(diào)用函數(shù)方式
函數(shù)還是上述的函數(shù)
main
func main() {//開(kāi)始時(shí)間var start_time = time.Now()//啟動(dòng)10個(gè)say說(shuō)話(huà)for i := 0; i < 10; i++ {go Say()}//結(jié)束時(shí)間var end_time = time.Now()//計(jì)算時(shí)間差fmt.Println(end_time.Sub(start_time))}
注意:第6行,前面加了個(gè)go關(guān)鍵字,go關(guān)鍵字就表示以一個(gè)微線(xiàn)程的方式單獨(dú)運(yùn)行這個(gè)函數(shù)。
執(zhí)行結(jié)果

what??? ? 0s,什么情況?
為什么會(huì)出現(xiàn)0s這種情況
這是因?yàn)椋贕o中,我們采用的是守護(hù)線(xiàn)程的方式,什么意思呢?

在Go中,main函數(shù)只要執(zhí)行完,其他微線(xiàn)程必涼。
就像有的怪獸,他們是互相依賴(lài)一個(gè)母體的,母體掛了,下面的娃也必掛。
所以該怎么解決這個(gè)問(wèn)題呢???
sync.WaitGroup
上述我們發(fā)現(xiàn),啟動(dòng)了一些微線(xiàn)程,但是微線(xiàn)程還沒(méi)來(lái)得及執(zhí)行就掛了,是因?yàn)?/span>main函數(shù)跑的太快了,main跑完了,Go運(yùn)行時(shí)自動(dòng)將其他微線(xiàn)程關(guān)閉了。
那反過(guò)來(lái)想,我們?nèi)绾巫?/span>main在最后等一下,等我的孩子們都回來(lái)了,我在繼續(xù)跑。
所以,有一個(gè)新的問(wèn)題,那就是等,祭出法寶sync.WaitGroup
先看一下怎么用
函數(shù)
func Say() {//函數(shù)結(jié)束時(shí)取消標(biāo)記defer wg.Done()//每個(gè)函數(shù)在啟動(dòng)時(shí)加上一個(gè)標(biāo)記wg.Add(1)//函數(shù)開(kāi)始打上一個(gè)標(biāo)記time.Sleep(time.Second*1)fmt.Println("我在說(shuō)話(huà)說(shuō)了1s說(shuō)完了...")}
main
var wg sync.WaitGroupfunc main() {//開(kāi)始時(shí)間var start_time = time.Now()//啟動(dòng)10個(gè)say說(shuō)話(huà)for i := 0; i < 10; i++ {go Say()}// 等待所有標(biāo)記過(guò)的微線(xiàn)程執(zhí)行完畢wg.Wait()//結(jié)束時(shí)間var end_time = time.Now()//計(jì)算時(shí)間差fmt.Println(end_time.Sub(start_time))}
執(zhí)行結(jié)果

可以看到,10個(gè)線(xiàn)程同時(shí)啟動(dòng),1s就完了,并且代碼相對(duì)簡(jiǎn)單,就算開(kāi)啟10w個(gè),還是1s多一點(diǎn)
這也是為什么很多公司越來(lái)越青睞Go的原因。

runtime.GOMAXPROCS
這個(gè)意思要使用多少個(gè)核,默認(rèn)使用全部核心,性能跑滿(mǎn),但是也有意外的情況,
比如一個(gè)機(jī)器跑了很多其他任務(wù),Go寫(xiě)的這個(gè)是不太重要的任務(wù),但是是計(jì)算型的,這時(shí)候理論來(lái)說(shuō)是不盡量擠兌別人的算力
所以要限制一下當(dāng)前程序使用電腦的算力
代碼
func main() {//本機(jī)的cpu個(gè)數(shù)var cpuNum = runtime.NumCPU()fmt.Println(cpuNum)//設(shè)置Go使用cpu個(gè)數(shù)runtime.GOMAXPROCS(4)}
總結(jié)
上述我們學(xué)習(xí)了Go的并發(fā),學(xué)習(xí)了
如何創(chuàng)建一個(gè)協(xié)程(goroutine)。
為什么需要
sync.WaitGroup。設(shè)置當(dāng)前程序使用CPU核數(shù)。
在Go中,輕松實(shí)現(xiàn)一個(gè)高并發(fā)還是挺容易的,但是可能有些不是那么好理解。
如果在操作過(guò)程中有任何問(wèn)題,記得下面留言,我們看到會(huì)第一時(shí)間解決問(wèn)題。
我是碼農(nóng)星期八,如果覺(jué)得還不錯(cuò),記得動(dòng)手點(diǎn)贊一下哈。
感謝你的觀看。
想了解更多關(guān)于Go的知識(shí),請(qǐng)前往:http://pdcfighting.com/
-------------------?End?-------------------
往期精彩文章推薦:

歡迎大家點(diǎn)贊,留言,轉(zhuǎn)發(fā),轉(zhuǎn)載,感謝大家的相伴與支持
想加入Go學(xué)習(xí)群請(qǐng)?jiān)诤笈_(tái)回復(fù)【入群】
萬(wàn)水千山總是情,點(diǎn)個(gè)【在看】行不行
