這篇“Go語(yǔ)言中g(shù)oroutine怎么創(chuàng)建”文章的知識(shí)點(diǎn)大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價(jià)值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來(lái)看看這篇“Go語(yǔ)言中g(shù)oroutine怎么創(chuàng)建”文章吧。
創(chuàng)新互聯(lián)是專業(yè)的瑯琊網(wǎng)站建設(shè)公司,瑯琊接單;提供成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站制作,網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行瑯琊網(wǎng)站開發(fā)網(wǎng)頁(yè)制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來(lái)合作!
goroutine是Go語(yǔ)言中的輕量級(jí)線程實(shí)現(xiàn),是建立在線程之上的輕量級(jí)的抽象,由Go運(yùn)行時(shí)(runtime)管理。goroutine允許我們以非常低的代價(jià)在同一個(gè)地址空間中并行地執(zhí)行多個(gè)函數(shù)或者方法;相比于線程,它的創(chuàng)建和銷毀的代價(jià)要小很多,并且它的調(diào)度是獨(dú)立于線程的。
在編寫 Socket 網(wǎng)絡(luò)程序時(shí),需要提前準(zhǔn)備一個(gè)線程池為每一個(gè) Socket 的收發(fā)包分配一個(gè)線程。開發(fā)人員需要在線程數(shù)量和 CPU 數(shù)量間建立一個(gè)對(duì)應(yīng)關(guān)系,以保證每個(gè)任務(wù)能及時(shí)地被分配到 CPU 上進(jìn)行處理,同時(shí)避免多個(gè)任務(wù)頻繁地在線程間切換執(zhí)行而損失效率。
雖然,線程池為邏輯編寫者提供了線程分配的抽象機(jī)制。但是,如果面對(duì)隨時(shí)隨地可能發(fā)生的并發(fā)和線程處理需求,線程池就不是非常直觀和方便了。能否有一種機(jī)制:使用者分配足夠多的任務(wù),系統(tǒng)能自動(dòng)幫助使用者把任務(wù)分配到 CPU 上,讓這些任務(wù)盡量并發(fā)運(yùn)作。這種機(jī)制在 Go語(yǔ)言中被稱為 goroutine。
goroutine 是 Go語(yǔ)言中的輕量級(jí)線程實(shí)現(xiàn),由 Go 運(yùn)行時(shí)(runtime)管理。Go 程序會(huì)智能地將 goroutine 中的任務(wù)合理地分配給每個(gè) CPU。
Goroutine是建立在線程之上的輕量級(jí)的抽象。它允許我們以非常低的代價(jià)在同一個(gè)地址空間中并行地執(zhí)行多個(gè)函數(shù)或者方法。相比于線程,它的創(chuàng)建和銷毀的代價(jià)要小很多,并且它的調(diào)度是獨(dú)立于線程的。
Go 程序從 main 包的 main() 函數(shù)開始,在程序啟動(dòng)時(shí),Go 程序就會(huì)為 main() 函數(shù)創(chuàng)建一個(gè)默認(rèn)的 goroutine。
使用普通函數(shù)創(chuàng)建 goroutine
Go 程序中使用 go 關(guān)鍵字為一個(gè)函數(shù)創(chuàng)建一個(gè) goroutine。一個(gè)函數(shù)可以被創(chuàng)建多個(gè) goroutine,一個(gè) goroutine 必定對(duì)應(yīng)一個(gè)函數(shù)。
1) 格式
為一個(gè)普通函數(shù)創(chuàng)建 goroutine 的寫法如下:
go 函數(shù)名( 參數(shù)列表 )
函數(shù)名:要調(diào)用的函數(shù)名。
參數(shù)列表:調(diào)用函數(shù)需要傳入的參數(shù)。
使用 go 關(guān)鍵字創(chuàng)建 goroutine 時(shí),被調(diào)用函數(shù)的返回值會(huì)被忽略。
如果需要在 goroutine 中返回?cái)?shù)據(jù),請(qǐng)使用后面介紹的通道(channel)特性,通過(guò)通道把數(shù)據(jù)從 goroutine 中作為返回值傳出。
2) 例子
使用 go 關(guān)鍵字,將 running() 函數(shù)并發(fā)執(zhí)行,每隔一秒打印一次計(jì)數(shù)器,而 main 的 goroutine 則等待用戶輸入,兩個(gè)行為可以同時(shí)進(jìn)行。請(qǐng)參考下面代碼:
package main
import (
"fmt"
"time"
)
func running() {
var times int
// 構(gòu)建一個(gè)無(wú)限循環(huán)
for {
times++
fmt.Println("tick", times)
// 延時(shí)1秒
time.Sleep(time.Second)
}
}
func main() {
// 并發(fā)執(zhí)行程序
go running()
// 接受命令行輸入, 不做任何事情
var input string
fmt.Scanln(&input)
}
命令行輸出如下:
代碼執(zhí)行后,命令行會(huì)不斷地輸出 tick,同時(shí)可以使用 fmt.Scanln() 接受用戶輸入。兩個(gè)環(huán)節(jié)可以同時(shí)進(jìn)行。
代碼說(shuō)明如下:
第 12 行,使用 for 形成一個(gè)無(wú)限循環(huán)。
第 13 行,times 變量在循環(huán)中不斷自增。
第 14 行,輸出 times 變量的值。
第 17 行,使用 time.Sleep 暫停 1 秒后繼續(xù)循環(huán)。
第 25 行,使用 go 關(guān)鍵字讓 running() 函數(shù)并發(fā)運(yùn)行。
第 29 行,接受用戶輸入,直到按 Enter 鍵時(shí)將輸入的內(nèi)容寫入 input 變量中并返回,整個(gè)程序終止。
這段代碼的執(zhí)行順序如下圖所示。
圖:并發(fā)運(yùn)行圖
這個(gè)例子中,Go 程序在啟動(dòng)時(shí),運(yùn)行時(shí)(runtime)會(huì)默認(rèn)為 main() 函數(shù)創(chuàng)建一個(gè) goroutine。在 main() 函數(shù)的 goroutine 中執(zhí)行到 go running 語(yǔ)句時(shí),歸屬于 running() 函數(shù)的 goroutine 被創(chuàng)建,running() 函數(shù)開始在自己的 goroutine 中執(zhí)行。此時(shí),main() 繼續(xù)執(zhí)行,兩個(gè) goroutine 通過(guò) Go 程序的調(diào)度機(jī)制同時(shí)運(yùn)作。
使用匿名函數(shù)創(chuàng)建goroutine
go 關(guān)鍵字后也可以為匿名函數(shù)或閉包啟動(dòng) goroutine。
1) 使用匿名函數(shù)創(chuàng)建goroutine的格式
使用匿名函數(shù)或閉包創(chuàng)建 goroutine 時(shí),除了將函數(shù)定義部分寫在 go 的后面之外,還需要加上匿名函數(shù)的調(diào)用參數(shù),格式如下:
go func( 參數(shù)列表 ){
函數(shù)體
}( 調(diào)用參數(shù)列表 )
其中:
參數(shù)列表:函數(shù)體內(nèi)的參數(shù)變量列表。
函數(shù)體:匿名函數(shù)的代碼。
調(diào)用參數(shù)列表:?jiǎn)?dòng) goroutine 時(shí),需要向匿名函數(shù)傳遞的調(diào)用參數(shù)。
2) 使用匿名函數(shù)創(chuàng)建goroutine的例子
在 main() 函數(shù)中創(chuàng)建一個(gè)匿名函數(shù)并為匿名函數(shù)啟動(dòng) goroutine。匿名函數(shù)沒有參數(shù)。代碼將并行執(zhí)行定時(shí)打印計(jì)數(shù)的效果。參見下面的代碼:
package main
import (
"fmt"
"time"
)
func main() {
go func() {
var times int
for {
times++
fmt.Println("tick", times)
time.Sleep(time.Second)
}
}()
var input string
fmt.Scanln(&input)
}
代碼說(shuō)明如下:
第 10 行,go 后面接匿名函數(shù)啟動(dòng) goroutine。
第 12~19 行的邏輯與前面程序的 running() 函數(shù)一致。
第 21 行的括號(hào)的功能是調(diào)用匿名函數(shù)的參數(shù)列表。由于第 10 行的匿名函數(shù)沒有參數(shù),因此第 21 行的參數(shù)列表也是空的。
擴(kuò)展知識(shí):Goroutine與線程的區(qū)別
許多人認(rèn)為goroutine比線程運(yùn)行得更快,這是一個(gè)誤解。Goroutine并不會(huì)更快,它只是增加了更多的并發(fā)性。當(dāng)一個(gè)goroutine被阻塞(比如等待IO),golang的scheduler會(huì)調(diào)度其他可以執(zhí)行的goroutine運(yùn)行。與線程相比,它有以下的幾個(gè)優(yōu)點(diǎn):
內(nèi)存消耗更少:
Goroutine所需要的內(nèi)存通常只有2kb,而線程則需要1Mb(500倍)
創(chuàng)建與銷毀的開銷更小:
由于線程創(chuàng)建時(shí)需要向操作系統(tǒng)申請(qǐng)資源,并且在銷毀時(shí)將資源歸還,因此它的創(chuàng)建和銷毀的開銷比較大。相比之下,goroutine的創(chuàng)建和銷毀是由go語(yǔ)言在運(yùn)行時(shí)自己管理的,因此開銷更低。
切換開銷更小:
只是goroutine之于線程的主要區(qū)別,也是golang能夠?qū)崿F(xiàn)高并發(fā)的主要原因。線程的調(diào)度方式是搶占式的,如果一個(gè)線程的執(zhí)行時(shí)間超過(guò)了分配給它的時(shí)間片,就會(huì)被其他可執(zhí)行的線程搶占。在線程切換的過(guò)程中需要保存/恢復(fù)所有的寄存器信息,比如16個(gè)通用寄存器,PC(Program Counter)、SP(Stack Pointer)段寄存器等等。而goroutine的調(diào)度是協(xié)同式的,它不會(huì)直接地與操作系統(tǒng)內(nèi)核打交道。當(dāng)goroutine進(jìn)行切換的時(shí)候,之后很少量的寄存器需要保存和恢復(fù)(PC和SP)。因此goroutine的切換效率更高。
以上就是關(guān)于“Go語(yǔ)言中g(shù)oroutine怎么創(chuàng)建”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對(duì)大家有幫助,若想了解更多相關(guān)的知識(shí)內(nèi)容,請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。