并發(fā)模式之外延
協(xié)程相較于線(xiàn)程,可以大量創(chuàng)建。打開(kāi)這扇門(mén),我們拓展出新的用法,可以做生成器,可以讓函數(shù)返回“服務(wù)”,可以讓循環(huán)并發(fā)執(zhí)行,還能共享變量。但是出現(xiàn)新 的用法的同時(shí),也帶來(lái)了新的棘手問(wèn)題,協(xié)程也會(huì)泄漏,不恰當(dāng)?shù)氖褂脮?huì)影響性能。下面會(huì)逐一介紹各種用法和問(wèn)題。演示的代碼用GO語(yǔ)言寫(xiě)成,因?yàn)槠浜?jiǎn)潔明 了,而且支持全部功能。
生成器
有的時(shí)候,我們需要有一個(gè)函數(shù)能不斷生成數(shù)據(jù)。比方說(shuō)這個(gè)函數(shù)可以讀文件,讀網(wǎng)絡(luò),生成自增長(zhǎng)序列,生成隨機(jī)數(shù)。這些行為的特點(diǎn)就是,函數(shù)的已知一些變量,如文件路徑。然后不斷調(diào)用,返回新的數(shù)據(jù)。
下面生成隨機(jī)數(shù)為例,以讓我們做一個(gè)會(huì)并發(fā)執(zhí)行的隨機(jī)數(shù)生成器。
非并發(fā)的做法是這樣的:
// 函數(shù)rand_generator_1 ,返回 int
funcrand_generator_1() int {
return rand.Int()
}
上面是一個(gè)函數(shù),返回一個(gè)int。假如rand.Int()這個(gè)函數(shù)調(diào)用需要很長(zhǎng)時(shí)間等待,那該函數(shù)的調(diào)用者也會(huì)因此而掛起。所以我們可以創(chuàng)建一個(gè)協(xié)程,專(zhuān)門(mén)執(zhí)行rand.Int()。
// 函數(shù)rand_generator_2,返回通道(Channel)
funcrand_generator_2() chan int {
// 創(chuàng)建通道
out := make(chan int)
// 創(chuàng)建協(xié)程
go func() {
for {
//向通道內(nèi)寫(xiě)入數(shù)據(jù),如果無(wú)人讀取會(huì)等待
out <- rand.Int()
}
}()
return out
}
funcmain() {
// 生成隨機(jī)數(shù)作為一個(gè)服務(wù)
rand_service_handler :=rand_generator_2()
// 從服務(wù)中讀取隨機(jī)數(shù)并打印
fmt.Printf("%d\n",<-rand_service_handler)
}
上面的這段函數(shù)就可以并發(fā)執(zhí)行了rand.Int()。有一點(diǎn)值得注意到函數(shù)的返回可以理解為一個(gè)“服務(wù)”。但我們需要獲取隨機(jī)數(shù)據(jù)時(shí)候,可以隨時(shí)向這個(gè) 服務(wù)取用,他已經(jīng)為我們準(zhǔn)備好了相應(yīng)的數(shù)據(jù),無(wú)需等待,隨要隨到。如果我們調(diào)用這個(gè)服務(wù)不是很頻繁,一個(gè)協(xié)程足夠滿(mǎn)足我們的需求了。但如果我們需要大量訪(fǎng) 問(wèn),怎么辦?我們可以用下面介紹的多路復(fù)用技術(shù),啟動(dòng)若干生成器,再將其整合成一個(gè)大的服務(wù)。
調(diào)用生成器,可以返回一個(gè)“服務(wù)”?梢杂迷诔掷m(xù)獲取數(shù)據(jù)的場(chǎng)合。用途很廣泛,讀取數(shù)據(jù),生成ID,甚至定時(shí)器。這是一種非常簡(jiǎn)潔的思路,將程序并發(fā)化。