鍍金池/ 教程/ GO/ 并發(fā)
版權(quán)
簡(jiǎn)介
Bibliography
接口
通訊
函數(shù)
進(jìn)階
索引
并發(fā)

并發(fā)

在這章中將展示 Go 使用 channel 和 goroutine 開(kāi)發(fā)并行程序的能力。goroutine 是 Go并發(fā)能力的核心要素。但是,goroutine 到底是什么?來(lái)自 [8]:

叫做 goroutine 是因?yàn)橐延械亩陶Z(yǔ)——線程、協(xié)程、進(jìn)程等等——傳遞了不準(zhǔn)確的含義。goroutine 有簡(jiǎn)單的模型:它是與其他 goroutine 并行執(zhí)行的,有著相同地址空間的函數(shù)。它是輕量的,僅比分配??臻g多一點(diǎn)點(diǎn)消耗。而初始時(shí)棧是很小的,所以它們也是廉價(jià)的,并且隨著需要在堆空間上分配(和釋放)。

goroutine 是一個(gè)普通的函數(shù),只是需要使用關(guān)鍵字 go 作為開(kāi)頭。

http://wiki.jikexueyuan.com/project/learn-go-language/images/167.png" alt="pic" />

下面程序的思路來(lái)自 [20]。讓一個(gè)函數(shù)作為兩個(gè) goroutine 執(zhí)行,goroutine 等待一段時(shí)間,然后打印一些內(nèi)容到屏幕。在第 14 和 15 行,啟動(dòng)了 goroutine。main 函數(shù)等待足夠的長(zhǎng)的時(shí)間,這樣每個(gè) goroutine 會(huì)打印各自的文本到屏幕?,F(xiàn)在是在第 17 行等待 5 秒鐘,但實(shí)際上沒(méi)有任何辦法知道,當(dāng)所有 goroutine 都已經(jīng)退出應(yīng)當(dāng)?shù)却嗑谩?/p>

http://wiki.jikexueyuan.com/project/learn-go-language/images/168.png" alt="pic" />

如果不等待 goroutine 的執(zhí)行(例如,移除第 17 行),程序立刻終止,而任何正在執(zhí)行的 goroutine 都會(huì)停止。為了修復(fù)這個(gè),需要一些能夠同 goroutine 通訊的機(jī)制。這一機(jī)制通過(guò) channels 的形式使用。channel 可以與 Unix sehll 中的雙向管道做類比:可以通過(guò)它發(fā)送或者接收值。這些值只能是特定的類型:channel 類型。定義一個(gè) channel時(shí),也需要定義發(fā)送到 channel 的值的類型。注意,必須使用 make 創(chuàng)建 channel:

ci := make(chan i n t )
cs := make(chan s t r i n g )
cf := make(chan i n t e r f a c e { })

創(chuàng)建 channel ci 用于發(fā)送和接收整數(shù),創(chuàng)建 channel cs 用于字符串,以及 channel cf 使用了空接口來(lái)滿足各種類型。向 channel 發(fā)送或接收數(shù)據(jù),是通過(guò)類似的操作符完成的:<-. 具體作用則依賴于操作符的位置:

http://wiki.jikexueyuan.com/project/learn-go-language/images/169.png" alt="pic" />

將這些放到實(shí)例中去。

http://wiki.jikexueyuan.com/project/learn-go-language/images/170.png" alt="pic" />

0 .定義 c 作為 int 型的 channel。就是說(shuō):這個(gè) channel 傳輸整數(shù)。注意這個(gè)變量是全局的,這樣 goroutine 可以訪問(wèn)它;

  1. 發(fā)送整數(shù) 1 到 channel c;
  2. 初始化 c;
  3. 用關(guān)鍵字 go 開(kāi)始一個(gè) goroutine;
  4. 等待,直到從 channel 上接收一個(gè)值。注意,收到的值被丟棄了;
  5. 兩個(gè) goroutines,接收兩個(gè)值。

這里仍然有一些丑陋的東西;不得不從 channel 中讀取兩次(第 14 和 15 行)。在這個(gè)例子中沒(méi)問(wèn)題,但是如果不知道有啟動(dòng)了多少個(gè) goroutine 怎么辦呢?這里有另一個(gè) Go 內(nèi)建的關(guān)鍵字:select。通過(guò) select(和其他東西)可以監(jiān)聽(tīng) channel 上輸入的數(shù)據(jù)。

在這個(gè)程序中使用 select,并不會(huì)讓它變得更短,因?yàn)檫\(yùn)行的 goroutine 太少了。移除第 14 和 15 行,并用下面的內(nèi)容替換它們:

http://wiki.jikexueyuan.com/project/learn-go-language/images/171.png" alt="pic" />

現(xiàn)在將會(huì)一直等待下去。只有當(dāng)從 channel c 上收到多個(gè)響應(yīng)時(shí)才會(huì)退出循環(huán) L。

使其并行運(yùn)行

雖然 goroutine 是并發(fā)執(zhí)行的,但是它們并不是并行運(yùn)行的。如果不告訴 Go 額外的東西,同一時(shí)刻只會(huì)有一個(gè) goroutine 執(zhí)行。利用 runtime.GOMAXPROCS(n) 可以設(shè)置 goroutine 并行執(zhí)行的數(shù)量。來(lái)自文檔:

GOMAXPROCS 設(shè)置了同時(shí)運(yùn)行的 CPU 的最大數(shù)量,并返回之前的設(shè)置。如 果 n < 1,不會(huì)改變當(dāng)前設(shè)置。當(dāng)調(diào)度得到改進(jìn)后,這將被移除。

如果不希望修改任何源代碼,同樣可以通過(guò)設(shè)置環(huán)境變量 GOMAXPROCS 為目標(biāo)值。

更多關(guān)于 channel

當(dāng)在 Go 中用 ch := make(chan bool) 創(chuàng)建 chennel 時(shí),bool 型的無(wú)緩沖 channel 會(huì)被創(chuàng)建。這對(duì)于程序來(lái)說(shuō)意味著什么呢?首先,如果讀?。╲alue := <

下一篇:接口