1. 程式人生 > >Golang併發模型:輕鬆入門流水線模型

Golang併發模型:輕鬆入門流水線模型

Golang作為一個實用主義的程式語言,非常注重效能,在語言特性上天然支援併發,它有多種併發模型,通過流水線模型系列文章,你會更好的使用Golang併發特性,提高你的程式效能。

這篇文章主要介紹流水線模型的流水線概念,後面文章介紹流水線模型的FAN-IN和FAN-OUT,最後介紹下如何合理的關閉流水線的協程。

Golang的併發核心思路

Golang併發核心思路是關注資料流動。資料流動的過程交給channel,資料處理的每個環節都交給goroutine,把這些流程畫起來,有始有終形成一條線,那就能構成流水線模型。

但我們先從簡單的入手。

從一個簡單的流水線入手

流水線並不是什麼新奇的概念,它能極大的提高生產效率,在當代社會流水線非常普遍,我們用的幾乎任何產品(手機、電腦、汽車、水杯),都是從流水線上生產出來的。以汽車為例,整個汽車流水線要經過幾百個組裝點,而在某個組裝點只組裝固定的零部件,然後傳遞給下一個組裝點,最終一臺完整的汽車從流水線上生產出來。

car_pipeline.jpeg

Golang的併發模型靈感其實都來自我們生活,對軟體而言,高的生產效率就是高的效能。

在Golang中,流水線由多個階段組成,每個階段之間通過channel連線,每個節點可以由多個同時執行的goroutine組成。

從最簡單的流水線入手。下圖的流水線由3個階段組成,分別是A、B、C,A和B之間是通道aCh

,B和C之間是通道bCh,A生成資料傳遞給B,B生成資料傳遞給C。

流水線中,第一個階段的協程是生產者,它們只生產資料。最後一個階段的協程是消費者,它們只消費資料。下圖中A是生成者,C是消費者,而B只是中間過程的處理者。

簡單流水線.png

舉個例子,設計一個程式:計算一個整數切片中元素的平方值並把它打印出來。非併發的方式是使用for遍歷整個切片,然後計算平方,列印結果。

我們使用流水線模型實現這個簡單的功能,從流水線的角度,可以分為3個階段:

  1. 遍歷切片,這是生產者。
  2. 計算平方值。
  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

這是一種原始的流水線模型,這種原始能讓我們掌握流水線的思路。

流水線的特點

  1. 每個階段把資料通過channel傳遞給下一個階段。
  2. 每個階段要建立1個goroutine和1個通道,這個goroutine向裡面寫資料,函式要返回這個通道。
  3. 有1個函式來組織流水線,我們例子中是main函式。

如果你沒了解過流水線,建議自己把以上的程式寫一遍,如果遇到問題解決了,那才真正掌握了流水線模型的思路。

完整示例程式碼

本文所有程式碼都在倉庫,可檢視完整示例程式碼:https://github.com/Shitaibin/golang_pipeline_step_by_step

併發系列文章推薦

下一篇,我將介紹流水線模型的FAN-IN、FAN-OUT,歡迎關注。

  1. 如果這篇文章對你有幫助,不妨關注下我的Github,有文章會收到通知。
  2. 本文作者:大彬
  3. 如果喜歡本文,隨意轉載,但請保留此原文連結:http://lessisbetter.site/2018/11/16/golang-introduction-to-pipeline/
關注公眾號,獲取最新Golang文章。 一起學Golang-分享有料的Go語言技術