這篇文章主要講解了“go語言協(xié)程指的是什么”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“go語言協(xié)程指的是什么”吧!
公司主營業(yè)務(wù):成都做網(wǎng)站、成都網(wǎng)站制作、移動網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競爭能力。創(chuàng)新互聯(lián)是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對我們的高要求,感謝他們從不同領(lǐng)域給我們帶來的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會用頭腦與智慧不斷的給客戶帶來驚喜。創(chuàng)新互聯(lián)推出隨州免費(fèi)做網(wǎng)站回饋大家。
在go語言中,協(xié)程(goroutine)是指在后臺中運(yùn)行的輕量級執(zhí)行線程;go協(xié)程是Go中實(shí)現(xiàn)并發(fā)的關(guān)鍵組成部分。Go中提供了一個關(guān)鍵字go來創(chuàng)建一個Go協(xié)程,當(dāng)在函數(shù)或方法的調(diào)用之前添加一個關(guān)鍵字go,這樣就開啟了一個Go協(xié)程,該函數(shù)或者方法就會在這個Go協(xié)程中運(yùn)行。
Go 協(xié)程 (goroutine) 是指在后臺中運(yùn)行的輕量級執(zhí)行線程,go 協(xié)程是 Go 中實(shí)現(xiàn)并發(fā)的關(guān)鍵組成部分。
由于 Go 協(xié)程相對于傳統(tǒng)操作系統(tǒng)中的線程 (thread) 是非常輕量級的,因此對于一個典型的 Go 應(yīng)用來說,有數(shù)以千計(jì)的 Go 協(xié)程并發(fā)運(yùn)行的情形是十分常見的。并發(fā)可以顯著地提升應(yīng)用的運(yùn)行速度,并且可以幫助我們編寫關(guān)注點(diǎn)分離(Separation of concerns,Soc)的代碼。
我們也許在理論上已經(jīng)知曉 Go 協(xié)程是如何工作的,但是在代碼層級上,go 協(xié)程何許物也?其實(shí),go 協(xié)程看起來只是一個與其他眾 Go 協(xié)程并發(fā)運(yùn)行的一個簡單函數(shù)或者方法,但是我們并不能想當(dāng)然地從函數(shù)或者方法中的定義來確定一個 Go 協(xié)程,go 協(xié)程的確定還是要取決于我們?nèi)绾稳フ{(diào)用。
Go 中提供了一個關(guān)鍵字 go
來讓我們創(chuàng)建一個 Go 協(xié)程,當(dāng)我們在函數(shù)或方法的調(diào)用之前添加一個關(guān)鍵字 go
,這樣我們就開啟了一個 Go 協(xié)程,該函數(shù)或者方法就會在這個 Go 協(xié)程中運(yùn)行。
舉個簡單的栗子:
在上面的代碼中,我們定義了一個可以在控制臺輸出 Hello World
字符串的 printHello
的函數(shù),在 main
函數(shù)中,我們就像平時那樣調(diào)用 printHello
函數(shù),最終也是理所當(dāng)然地獲得了期望的結(jié)果。
下面,讓我們嘗試從同一個函數(shù)創(chuàng)建 Go 協(xié)程:
根據(jù) Go 協(xié)程的語法,我們在函數(shù)調(diào)用的前面增加了一個 go
關(guān)鍵字,之后程序運(yùn)行正常,輸出了以下的結(jié)果:
main execution started
main execution stopped
奇怪的是,Hello World
并沒有如同我們預(yù)料的那樣輸出,這期間究竟發(fā)生了什么?
go 協(xié)程總是在后臺運(yùn)行,當(dāng)一個 Go 協(xié)程執(zhí)行的時候(在這個例子中是 go printHello()
), Go 并不會像在之前的那個例子中在執(zhí)行 printHello
中的功能時阻塞 main 函數(shù)中剩下語句的執(zhí)行,而是直接忽略了 Go 協(xié)程的返回并繼續(xù)執(zhí)行 main 函數(shù)剩下的語句。即便如此,我們?yōu)槭裁礇]法看到函數(shù)的輸出呢?
在默認(rèn)情況下,每個獨(dú)立的 Go 應(yīng)用運(yùn)行時就創(chuàng)建了一個 Go 協(xié)程,其 main
函數(shù)就在這個 Go 協(xié)程中運(yùn)行,這個 Go 協(xié)程就被稱為 go 主協(xié)程(main Goroutine,下面簡稱主協(xié)程)
。在上面的例子中,主協(xié)程
中又產(chǎn)生了一個 printHello
這個函數(shù)的 Go 協(xié)程,我們暫且叫它 printHello 協(xié)程
吧,因而我們在執(zhí)行上面的程序的時候,就會存在兩個 Go 協(xié)程(main
和 printHello
)同時運(yùn)行。正如同以前的程序那樣,go 協(xié)程們會進(jìn)行協(xié)同調(diào)度。因此,當(dāng) 主協(xié)程
運(yùn)行的時候,Go 調(diào)度器在 主協(xié)程
執(zhí)行完之前并不會將控制權(quán)移交給 printHello 協(xié)程
。不幸的是,一旦 主協(xié)程
執(zhí)行完畢,整個程序會立即終止,調(diào)度器再也沒有時間留給 printHello 協(xié)程
去運(yùn)行了。
但正如我們從其他課程所知,通過阻塞條件,我們可以手動將控制權(quán)轉(zhuǎn)移給其他的 Go 協(xié)程 , 也可以說是告訴調(diào)度器讓它去調(diào)度其他可用空閑的 Go 協(xié)程。讓我們調(diào)用 time.Sleep()
函數(shù)去實(shí)現(xiàn)它吧。
如上圖所示,我們修改了程序,程序在 main 函數(shù)的最后一條語句之前調(diào)用了 time.Sleep(10 * time.Millisecond)
,使得 主協(xié)程
在執(zhí)行最后一條指令之前調(diào)度器就將控制權(quán)轉(zhuǎn)移給了 printhello 協(xié)程
。在這個例子中,我們通過調(diào)用 time.Sleep(10 * time.Millisecond)
強(qiáng)行讓 主協(xié)程
休眠 10ms 并且在在這個 10ms 內(nèi)不會再被調(diào)度器重新調(diào)度運(yùn)行。
一旦 printHello 協(xié)程
執(zhí)行,它就會向控制臺打印‘ Hello World !’,然后該 Go 協(xié)程(printHello 協(xié)程
)就會隨之終止,接下來 主協(xié)程
就會被重新調(diào)度(因?yàn)?main Go 協(xié)程已經(jīng)睡夠 10ms 了),并執(zhí)行最后一條語句。因此,運(yùn)行上面的程序就會得到以下的輸出 :
main execution started
Hello World!
main execution stopped
下面我稍微修改一下例子,我在 printHello
函數(shù)的輸出語句之前添加了一條 time.Sleep(time.Millisecond)
。我們已經(jīng)知道了如果我們在函數(shù)中調(diào)用了休眠(sleep)函數(shù),這個函數(shù)就會告訴 Go 調(diào)度器去調(diào)度其他可被調(diào)度的 Go 協(xié)程。在上一課中提到,只有非休眠(non-sleeping
)的 Go 協(xié)程才會被認(rèn)為是可被調(diào)度的,所以主協(xié)程在這休眠的 10ms 內(nèi)是不會被再次調(diào)度的。因此 主協(xié)程
先打印出“ main execution started ” 接著就創(chuàng)建了一個 printHello協(xié)程,需要注意此時的 主協(xié)程
還是非休眠狀態(tài)的,在這之后主協(xié)程就要調(diào)用休眠函數(shù)去睡 10ms,并且把這個控制權(quán)讓出來給printHello協(xié)程。printHello協(xié)程會先休眠 1ms 告訴調(diào)度器看看有沒有其他可調(diào)度的 Go 協(xié)程,在這個例子里顯然沒有其他可調(diào)度的 Go 協(xié)程了,所以在printHello協(xié)程結(jié)束了這 1ms 的休眠戶就會被調(diào)度器調(diào)度,接著就輸出了“ Hello World ”字符串,之后這個 Go 協(xié)程運(yùn)行結(jié)束。之后,主協(xié)程會在之后的幾毫秒被喚醒,緊接著就會輸出“ main execution stopped ”并且結(jié)束整個程序。
上面的程序依舊和之前的例子一樣,輸出以下相同的結(jié)果:
main execution started
Hello World!
main execution stopped
要是,我把這個printHello協(xié)程中的休眠 1 毫秒改成休眠 15 毫秒,這個結(jié)果又是如何呢?
在這個例子中,與其他的例子最大的區(qū)別就是printHello協(xié)程比主協(xié)程的休眠時間還要長,很明顯,主協(xié)程要比 printHello 協(xié)程喚醒要早,這樣的結(jié)果就是主協(xié)程即使喚醒后執(zhí)行完所有的語句,printHello 協(xié)程還是在休眠狀態(tài)。之前提到過,主協(xié)程比較特殊,如果主協(xié)程執(zhí)行結(jié)束后整個程序就要退出,所以 printHello 協(xié)程得不到機(jī)會去執(zhí)行下面的輸出的語句了,所以以上的程序的數(shù)據(jù)結(jié)果如下:
main execution started
main execution stopped
就像之前我所提到過的,你可以隨心所欲地創(chuàng)建多個 Go 協(xié)程。下面讓我們定義兩個簡單的函數(shù),一個是用于順序打印某個字符串中的每個字符,另一個是順序打印出某個整數(shù)切片中的每個數(shù)字。
在上圖中的程序中,我們連續(xù)地創(chuàng)建了兩個 Go 協(xié)程,程序輸出的結(jié)果如下:
main execution started
H e l l o 1 2 3 4 5
main execution stopped
上面的結(jié)果證實(shí)了 Go 協(xié)程是以合作式調(diào)度來運(yùn)作的。下面我們在每個函數(shù)中的輸出語句的下面添加一行 time.Sleep
,讓函數(shù)在輸出每個字符或數(shù)字后休息一段時間,好讓調(diào)度器調(diào)度其他可用的 Go 協(xié)程。
在上面的程序中,我又修改了一下輸出語句使得我們可以看到每個字符或數(shù)字的輸出時刻。理論上主協(xié)程會休眠 200ms,因此其他 Go 協(xié)程要趕在主協(xié)程喚醒之前做完自己的工作,因?yàn)橹鲄f(xié)程喚醒之后就會導(dǎo)致程序退出。getChars
協(xié)程每打印一個字符就會休眠 10ms,之后控制權(quán)就會傳給 getDigits
協(xié)程,getDigits
協(xié)程每打印一個數(shù)字后就休眠 30ms,若 getChars
協(xié)程喚醒,則會把控制權(quán)傳回 getChars
協(xié)程,如此往復(fù)。在代碼中可以看到,getChars
協(xié)程會在其他協(xié)程休眠的時候多次進(jìn)行打印字符以及休眠操作,所以我們預(yù)計(jì)可以看到輸出的字符比數(shù)字更具有連續(xù)性。
我們在 Windows 上運(yùn)行上面的程序,得到了以下的結(jié)果:
main execution started at time 0s
H at time 1.0012ms <-|
1 at time 1.0012ms | almost at the same time
e at time 11.0283ms <-|
l at time 21.0289ms | ~10ms apart
l at time 31.0416ms
2 at time 31.0416ms
o at time 42.0336ms
3 at time 61.0461ms <-|
4 at time 91.0647ms |
5 at time 121.0888ms | ~30ms apart
main execution stopped at time 200.3137ms | exiting after 200ms
通過以上輸出結(jié)果可以證明我們之前對輸出的討論。對于這個結(jié)果,我們可以通過下面的的程序運(yùn)行圖來解釋。需要注意的是,我們在圖中定義一個輸出語句大約會花費(fèi) 1ms 的 CPU 時間,而這個時間相對于 200ms 來說是可以忽略不計(jì)的。
現(xiàn)在我們已經(jīng)知道了如何去創(chuàng)建 Go 協(xié)程以及去如何去使用它。但是使用 time.Sleep
只是一個讓我們獲取理想結(jié)果的一個小技巧。在實(shí)際生產(chǎn)環(huán)境中,我們無法知曉一個 Go 協(xié)程到底需要執(zhí)行多長的時間,因而在 main 函數(shù)里面添加一個 time.Sleep
并不是一個解決問題的方法。我們希望 Go 協(xié)程在執(zhí)行完畢后告知主協(xié)程運(yùn)行的結(jié)果。在目前階段,我們還不知道如何向其他 Go 協(xié)程傳遞以及獲取數(shù)據(jù),簡而言之,就是與其他 Go 協(xié)程進(jìn)行通信。這就是 channels 引入的原因。我們會在下一次課中討論這個東西。
如果一個匿名函數(shù)可以退出,那么匿名 Go 協(xié)程也同樣可以退出。請參照functions
課程中的 即時調(diào)用函數(shù)(Immedietly invoked function)
來理解本節(jié)。讓我們修改一下之前 printHello
協(xié)程的例子:
結(jié)果非常明顯,因?yàn)槲覀兌x了匿名函數(shù),并在同一語句中作為 Go 協(xié)程執(zhí)行。
需要注意的是,所有的 Go 協(xié)程都是匿名的,因?yàn)槲覀儚?strong>并發(fā)(concurrency
一課中學(xué)到,go 協(xié)程是不存在標(biāo)識符的,在這里所謂的匿名 Go 協(xié)程只是通過匿名函數(shù)來創(chuàng)建的 Go 協(xié)程罷了。
感謝各位的閱讀,以上就是“go語言協(xié)程指的是什么”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對go語言協(xié)程指的是什么這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!
新聞標(biāo)題:go語言協(xié)程指的是什么
網(wǎng)站鏈接:http://muchs.cn/article48/gjsehp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制網(wǎng)站、網(wǎng)站排名、做網(wǎng)站、定制開發(fā)、搜索引擎優(yōu)化、外貿(mào)網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)