如果說(shuō)Go lang是靜態(tài)語(yǔ)言中的皇冠,那么,Goroutine就是并發(fā)編程方式中的鉆石。Goroutine是Go語(yǔ)言設(shè)計(jì)體系中最核心的精華,它非常輕量,一個(gè) Goroutine 只占幾 KB,并且這幾 KB 就足夠 Goroutine 運(yùn)行完,這就能在有限的內(nèi)存空間內(nèi)支持大量 Goroutine協(xié)程任務(wù),方寸之間,運(yùn)籌帷幄,用極少的成本獲取最高的效率,支持了更多的并發(fā),毫無(wú)疑問(wèn),Goroutine是比Python的協(xié)程原理事件循環(huán)更高級(jí)的并發(fā)異步編程方式。
成都創(chuàng)新互聯(lián)公司是一家專(zhuān)注于成都做網(wǎng)站、成都網(wǎng)站建設(shè)與策劃設(shè)計(jì),洛龍網(wǎng)站建設(shè)哪家好?成都創(chuàng)新互聯(lián)公司做網(wǎng)站,專(zhuān)注于網(wǎng)站建設(shè)十年,網(wǎng)設(shè)計(jì)領(lǐng)域的專(zhuān)業(yè)建站公司;建站業(yè)務(wù)涵蓋:洛龍等地區(qū)。洛龍做網(wǎng)站價(jià)格咨詢(xún):18980820575
為什么Goroutine比Python的事件循環(huán)高級(jí)?是因?yàn)镚o lang的調(diào)度模型GMP可以參與系統(tǒng)內(nèi)核線程中的調(diào)度,這里G為Goroutine,是被調(diào)度的最小單元;M是系統(tǒng)起了多少個(gè)線程;P為Processor,也就是CPU處理器,調(diào)度器的核心處理器,通常表示執(zhí)行上下文,用于匹配 M 和 G 。P 的數(shù)量不能超過(guò) GOMAXPROCS 配置數(shù)量,這個(gè)參數(shù)的默認(rèn)值為當(dāng)前電腦的總核心數(shù),通常一個(gè) P 可以與多個(gè) M 對(duì)應(yīng),但同一時(shí)刻,這個(gè) P 只能和其中一個(gè) M 發(fā)生綁定關(guān)系;M 被創(chuàng)建之后需要自行在 P 的 free list 中找到 P 進(jìn)行綁定,沒(méi)有綁定 P 的 M,會(huì)進(jìn)入阻塞狀態(tài),每一個(gè)P最多關(guān)聯(lián)256個(gè)G。
說(shuō)白了,就是GMP和Python一樣,也是維護(hù)一個(gè)任務(wù)隊(duì)列,只不過(guò)這個(gè)任務(wù)隊(duì)列是通過(guò)Goroutine來(lái)調(diào)度,怎么調(diào)度?通過(guò)Goroutine和系統(tǒng)線程M的協(xié)商,尋找非阻塞的通道,進(jìn)入P的本地小隊(duì)列,然后交給系統(tǒng)內(nèi)的CPU執(zhí)行,藉此,充分利用了CPU的多核資源。
而Python的協(xié)程方式僅僅停留在用戶(hù)態(tài),它沒(méi)法參與到線程內(nèi)核的調(diào)度,彌補(bǔ)方式是單線程多協(xié)程任務(wù)下開(kāi)多進(jìn)程,Go lang則是全權(quán)交給Goroutine,用戶(hù)不需要參與底層操作,同時(shí)又可以利用CPU的多核資源。
首先默認(rèn)情況下,golang程序還是由上自下的串行方式:
package main
import (
"fmt"
)
func job() {
fmt.Println("任務(wù)執(zhí)行")
}
func main() {
job()
fmt.Println("任務(wù)執(zhí)行完了")
}
程序返回:
任務(wù)執(zhí)行
任務(wù)執(zhí)行完了
這里job中的打印函數(shù)是先于main中的打印函數(shù)。
現(xiàn)在,在執(zhí)行job函數(shù)前面加上關(guān)鍵字go,也就是啟動(dòng)一個(gè)goroutine去執(zhí)行job這個(gè)函數(shù):
package main
import (
"fmt"
"time"
)
func job() {
fmt.Println("任務(wù)執(zhí)行")
}
func main() {
go job()
fmt.Println("任務(wù)執(zhí)行完了")
time.Sleep(time.Second)
}
注意,開(kāi)啟Goroutine是在函數(shù)執(zhí)行的時(shí)候開(kāi)啟,并非聲明的時(shí)候,程序返回:
任務(wù)執(zhí)行完了
任務(wù)執(zhí)行
可以看到,執(zhí)行順序顛倒了過(guò)來(lái),首先為什么會(huì)先打印任務(wù)執(zhí)行完了,是因?yàn)橄到y(tǒng)在創(chuàng)建新的Goroutine的時(shí)候需要耗費(fèi)一些資源,因?yàn)榫退阒挥袔譳b,也需要時(shí)間來(lái)創(chuàng)建,而此時(shí)main函數(shù)所在的goroutine是繼續(xù)執(zhí)行的。
第二,為什么要人為的把main函數(shù)延遲一秒鐘?
因?yàn)楫?dāng)main()函數(shù)返回的時(shí)候main所在的Goroutine就結(jié)束了,所有在main()函數(shù)中啟動(dòng)的goroutine會(huì)一同結(jié)束,所以這里必須人為的“阻塞”一下main函數(shù),讓它后于job結(jié)束,有點(diǎn)像公園如果要關(guān)門(mén)必須等最后一個(gè)游客走了才能關(guān),否則就把游客關(guān)在公園里了,出不去了。
與此同時(shí),此邏輯和Python中的線程阻塞邏輯非常一致,用過(guò)Python多線程的朋友肯定知道要想讓所有子線程都執(zhí)行完畢,必須阻塞主線程,不能讓主線程提前執(zhí)行完,這和Goroutine有異曲同工之妙。
在Go lang中實(shí)現(xiàn)并發(fā)編程就是如此輕松,我們還可以啟動(dòng)多個(gè)Goroutine:
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
func job(i int) {
defer wg.Done() // 協(xié)程結(jié)束就通知
fmt.Println("協(xié)程任務(wù)執(zhí)行", i)
}
func main() {
for i := 0; i < 10; i++ {
wg.Add(1) // 啟動(dòng)協(xié)程任務(wù)后入隊(duì)
go job(i)
}
wg.Wait() // 等待所有登記的goroutine都結(jié)束
fmt.Println("所有任務(wù)執(zhí)行完畢")
}
程序返回:
協(xié)程任務(wù)執(zhí)行 8
協(xié)程任務(wù)執(zhí)行 9
協(xié)程任務(wù)執(zhí)行 5
協(xié)程任務(wù)執(zhí)行 0
協(xié)程任務(wù)執(zhí)行 1
協(xié)程任務(wù)執(zhí)行 4
協(xié)程任務(wù)執(zhí)行 7
協(xié)程任務(wù)執(zhí)行 2
協(xié)程任務(wù)執(zhí)行 3
協(xié)程任務(wù)執(zhí)行 6
所有任務(wù)執(zhí)行完畢
這里我們摒棄了相對(duì)土鱉的time.Sleep(time.Second)方式,而是采用sync包的WaitGroup方式,原理是當(dāng)啟動(dòng)協(xié)程任務(wù)后,在WaitGroup登記,當(dāng)每個(gè)協(xié)程任務(wù)執(zhí)行完成后,通知WaitGroup,直到所有的協(xié)程任務(wù)都執(zhí)行完畢,然后再執(zhí)行main函數(shù)所在的協(xié)程,所以“所有任務(wù)執(zhí)行完畢”會(huì)在所有協(xié)程任務(wù)執(zhí)行完畢后再打印。
我們?cè)賮?lái)看看,如果是Python,會(huì)怎么做?
import asyncio
import random
async def job(i):
print("協(xié)程任務(wù)執(zhí)行{}".format(i))
await asyncio.sleep(random.randint(1,5))
print("協(xié)程任務(wù)結(jié)束{}".format(i))
async def main():
tasks = [asyncio.create_task(job(i)) for i in range(10)]
res = await asyncio.gather(*tasks)
if __name__ == '__main__':
asyncio.run(main())
程序返回:
協(xié)程任務(wù)執(zhí)行0
協(xié)程任務(wù)執(zhí)行1
協(xié)程任務(wù)執(zhí)行2
協(xié)程任務(wù)執(zhí)行3
協(xié)程任務(wù)執(zhí)行4
協(xié)程任務(wù)執(zhí)行5
協(xié)程任務(wù)執(zhí)行6
協(xié)程任務(wù)執(zhí)行7
協(xié)程任務(wù)執(zhí)行8
協(xié)程任務(wù)執(zhí)行9
協(xié)程任務(wù)結(jié)束0
協(xié)程任務(wù)結(jié)束1
協(xié)程任務(wù)結(jié)束3
協(xié)程任務(wù)結(jié)束6
協(xié)程任務(wù)結(jié)束9
協(xié)程任務(wù)結(jié)束8
協(xié)程任務(wù)結(jié)束2
協(xié)程任務(wù)結(jié)束4
協(xié)程任務(wù)結(jié)束5
協(xié)程任務(wù)結(jié)束7
可以看到,Python協(xié)程工作的前提是,必須在同一個(gè)事件循環(huán)中,同時(shí)邏輯內(nèi)必須由用戶(hù)來(lái)手動(dòng)切換,才能達(dá)到“并發(fā)”的工作方式,假設(shè),如果我們不手動(dòng)切換呢?
import asyncio
import random
async def job(i):
print("協(xié)程任務(wù)執(zhí)行{}".format(i))
print("協(xié)程任務(wù)結(jié)束{}".format(i))
async def main():
tasks = [asyncio.create_task(job(i)) for i in range(10)]
res = await asyncio.gather(*tasks)
if __name__ == '__main__':
asyncio.run(main())
程序返回:
協(xié)程任務(wù)執(zhí)行0
協(xié)程任務(wù)結(jié)束0
協(xié)程任務(wù)執(zhí)行1
協(xié)程任務(wù)結(jié)束1
協(xié)程任務(wù)執(zhí)行2
協(xié)程任務(wù)結(jié)束2
協(xié)程任務(wù)執(zhí)行3
協(xié)程任務(wù)結(jié)束3
協(xié)程任務(wù)執(zhí)行4
協(xié)程任務(wù)結(jié)束4
協(xié)程任務(wù)執(zhí)行5
協(xié)程任務(wù)結(jié)束5
協(xié)程任務(wù)執(zhí)行6
協(xié)程任務(wù)結(jié)束6
協(xié)程任務(wù)執(zhí)行7
協(xié)程任務(wù)結(jié)束7
協(xié)程任務(wù)執(zhí)行8
協(xié)程任務(wù)結(jié)束8
協(xié)程任務(wù)執(zhí)行9
協(xié)程任務(wù)結(jié)束9
一望而知,只要你不手動(dòng)切任務(wù),它就立刻回到了“串行”的工作方式,同步的執(zhí)行任務(wù),那么協(xié)程的意義在哪兒呢?
所以,歸根結(jié)底,Goroutine除了可以極大的利用系統(tǒng)多核資源,它還能幫助開(kāi)發(fā)者來(lái)切換協(xié)程任務(wù),簡(jiǎn)化開(kāi)發(fā)者的工作,說(shuō)白了就是,不懂協(xié)程工作原理,也能照貓畫(huà)虎寫(xiě)go lang代碼,但如果不懂協(xié)程工作原理的前提下,寫(xiě)Python協(xié)程并發(fā)邏輯呢?恐怕夠嗆吧。
綜上,Goroutine的工作方式,就是多個(gè)協(xié)程在多個(gè)線程上切換,既可以用到多核,又可以減少切換開(kāi)銷(xiāo)。但有光就有影,有利就有弊,Goroutine確實(shí)不需要開(kāi)發(fā)者過(guò)度參與,但這樣開(kāi)發(fā)者就少了很多自由度,一些定制化場(chǎng)景下,就只能采用單一的Goroutine手段,比如一些純IO密集型任務(wù)場(chǎng)景,像爬蟲(chóng),你有多少cpu的意義并不大,因?yàn)閏pu老是等著你的io操作,所以Python這種協(xié)程工作方式在純IO密集型任務(wù)場(chǎng)景下并不遜色于Goroutine。
網(wǎng)站題目:并發(fā)與并行,同步和異步,Go lang1.18入門(mén)精煉教程,由白丁入鴻儒,Go lang并發(fā)編程之GoroutineEP13
文章鏈接:http://chinadenli.net/article14/dsoicge.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站制作、動(dòng)態(tài)網(wǎng)站、ChatGPT、手機(jī)網(wǎng)站建設(shè)、外貿(mào)建站、網(wǎng)頁(yè)設(shè)計(jì)公司
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容