新聞中心
在編寫 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í)行而損失效率。

創(chuàng)新互聯(lián)建站主要從事網(wǎng)站建設(shè)、成都網(wǎng)站制作、網(wǎng)頁設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)印臺(tái),10年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):18982081108
雖然,線程池為邏輯編寫者提供了線程分配的抽象機(jī)制。但是,如果面對(duì)隨時(shí)隨地可能發(fā)生的并發(fā)和線程處理需求,線程池就不是非常直觀和方便了。能否有一種機(jī)制:使用者分配足夠多的任務(wù),系統(tǒng)能自動(dòng)幫助使用者把任務(wù)分配到 CPU 上,讓這些任務(wù)盡量并發(fā)運(yùn)作。這種機(jī)制在 Go語言中被稱為
goroutine。
goroutine 是 Go語言中的輕量級(jí)線程實(shí)現(xiàn),由 Go 運(yùn)行時(shí)(runtime)管理。Go 程序會(huì)智能地將 goroutine 中的任務(wù)合理地分配給每個(gè) CPU。
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)特性,通過通道把數(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è)無限循環(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)
}命令行輸出如下:
tick 1
tick 2
tick 3
tick 4
tick 5
代碼執(zhí)行后,命令行會(huì)不斷地輸出 tick,同時(shí)可以使用 fmt.Scanln() 接受用戶輸入。兩個(gè)環(huán)節(jié)可以同時(shí)進(jìn)行。
代碼說明如下:
第 12 行,使用 for 形成一個(gè)無限循環(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 語句時(shí),歸屬于 running() 函數(shù)的 goroutine 被創(chuàng)建,running() 函數(shù)開始在自己的 goroutine 中執(zhí)行。此時(shí),main() 繼續(xù)執(zhí)行,兩個(gè) goroutine 通過 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)
}代碼說明如下:
- 第 10 行,go 后面接匿名函數(shù)啟動(dòng) goroutine。
- 第 12~19 行的邏輯與前面程序的 running() 函數(shù)一致。
- 第 21 行的括號(hào)的功能是調(diào)用匿名函數(shù)的參數(shù)列表。由于第 10 行的匿名函數(shù)沒有參數(shù),因此第 21 行的參數(shù)列表也是空的。
提示
所有 goroutine 在 main() 函數(shù)結(jié)束時(shí)會(huì)一同結(jié)束。
goroutine 雖然類似于線程概念,但是從調(diào)度性能上沒有線程細(xì)致,而細(xì)致程度取決于 Go 程序的 goroutine 調(diào)度器的實(shí)現(xiàn)和運(yùn)行環(huán)境。
終止 goroutine 的最好方法就是自然返回 goroutine 對(duì)應(yīng)的函數(shù)。雖然可以用 golang.org/x/net/context 包進(jìn)行 goroutine 生命期深度控制,但這種方法仍然處于內(nèi)部試驗(yàn)階段,并不是官方推薦的特性。
截止 Go 1.9 版本,暫時(shí)沒有標(biāo)準(zhǔn)接口獲取 goroutine 的 ID。
當(dāng)前名稱:創(chuàng)新互聯(lián)GO教程:Go語言goroutine(輕量級(jí)線程)
鏈接URL:http://m.fisionsoft.com.cn/article/coijeoj.html


咨詢
建站咨詢
