Go做爲一個實用主義的編程語言,很是注重性能,在語言特性上自然支持併發,Go併發模型有多種模式,經過流水線模型系列文章,你會更好的使用Go的併發特性,提升的程序性能。git
這篇文章主要介紹流水線模型的流水線概念,後面文章介紹流水線模型的FAN-IN和FAN-OUT,最後介紹下如何合理的關閉流水線的協程。github
Golang併發核心思路是關注數據流動。數據流動的過程交給channel,數據處理的每一個環節都交給goroutine,把這些流程畫起來,善始善終造成一條線,那就能構成流水線模型。golang
但咱們先從簡單的入手。編程
流水線並非什麼新奇的概念,它能極大的提升生產效率,在當代社會流水線很是廣泛,咱們用的幾乎任何產品(手機、電腦、汽車、水杯),都是從流水線上生產出來的。以汽車爲例,整個汽車流水線要通過幾百個組裝點,而在某個組裝點只組裝固定的零部件,而後傳遞給下一個組裝點,最終一臺完整的汽車從流水線上生產出來。bash
Golang的併發模型靈感其實都來自咱們生活,對軟件而言,高的生產效率就是高的性能。併發
在Golang中,流水線由多個階段組成,每一個階段之間經過channel鏈接,每一個節點能夠由多個同時運行的goroutine組成。less
從最簡單的流水線入手。下圖的流水線由3個階段組成,分別是A、B、C,A和B之間是通道aCh
,B和C之間是通道bCh
,A生成數據傳遞給B,B生成數據傳遞給C。編程語言
流水線中,第一個階段的協程是生產者,它們只生產數據。最後一個階段的協程是消費者,它們只消費數據。下圖中A是生成者,C是消費者,而B只是中間過程的處理者。函數
舉個例子,設計一個程序:計算一個整數切片中元素的平方值並把它打印出來。非併發的方式是使用for遍歷整個切片,而後計算平方,打印結果。性能
咱們使用流水線模型實現這個簡單的功能,從流水線的角度,能夠分爲3個階段:
下面這段代碼:
producer()
負責生產數據,它會把數據寫入通道,並把它寫數據的通道返回。square()
負責從某個通道讀數字,而後計算平方,將結果寫入通道,並把它的輸出通道返回。main()
負責啓動producer和square,而且仍是消費者,讀取suqre的結果,並打印出來。package main import ( "fmt" ) func producer(nums ...int) <-chan int { out := make(chan int) go func() { defer close(out) for _, n := range nums { out <- n } }() return out } func square(inCh <-chan int) <-chan int { out := make(chan int) go func() { defer close(out) for n := range inCh { out <- n * n } }() return out } func main() { in := producer(1, 2, 3, 4) ch := square(in) // consumer for ret := range ch { fmt.Printf("%3d", ret) } fmt.Println() }
結果:
➜ awesome git:(master) ✗ go run hi.go 1 4 9 16
這是一種原始的流水線模型,這種原始能讓咱們掌握流水線的思路。
若是你沒了解過流水線,建議本身把以上的程序寫一遍,若是遇到問題解決了,那才真正掌握了流水線模型的思路。
下一篇,我將介紹流水線模型的FAN-IN、FAN-OUT,歡迎關注。
本文全部代碼都在倉庫,可查看完整示例代碼:https://github.com/Shitaibin/...
- 若是這篇文章對你有幫助,請點個贊/喜歡,鼓勵我持續分享,感謝。
- 個人文章列表,點此可查看
- 若是喜歡本文,隨意轉載,但請保留此原文連接。