1. 程式人生 > >golang 並發編程之生產者消費者

golang 並發編程之生產者消費者

單元 and func 之間 -m 內部實現 根據 inux ati

golang 最吸引人的地方可能就是並發了,無論代碼的編寫上,還是性能上面,golang 都有絕對的優勢

學習一個語言的並發特性,我喜歡實現一個生產者消費者模型,這個模型非常經典,適用於很多的並發場景,下面我通過這個模型,來簡單介紹一下 golang 的並發編程

go 並發語法

協程 go

協程是 golang 並發的最小單元,類似於其他語言的線程,只不過線程的實現借助了操作系統的實現,每次線程的調度都是一次系統調用,需要從用戶態切換到內核態,這是一項非常耗時的操作,因此一般的程序裏面線程太多會導致大量的性能耗費在線程切換上。而在 golang 內部實現了這種調度,協程在這種調度下面的切換非常的輕量級,成百上千的協程跑在一個 golang 程序裏面是很正常的事情

golang 為並發而生,啟動一個協程的語法非常簡單,使用 go 關鍵字即可

go func () {
    // do something
}

同步信號 sync.WaitGroup

多個協程之間可以通過 sync.WaitGroup 同步,這個類似於 Linux 裏面的信號量

var wg sync.WaitGroup  // 申明一個信號量
wg.Add(1)   // 信號量加一
wg.Done()   // 信號量減一
wg.Wait()   // 信號量為正時阻塞,直到信號量為0時被喚醒

通道 chan

通道可以理解為一個消息隊列,生產者往隊列裏面放,消費者從隊列裏面取。通道可以使用 close 關閉

ic := make(chan int, 10)  // 申明一個通道
ic <- 10        // 往通道裏面放
i := <- ic      // 從通道裏面取

close(ic)       // 關閉通道

生產者消費者實現

定義產品類

這個產品類根據具體的業務需求定義

type Product struct {
    name  int
    value int
}

生產者

如果 stop 標誌不為 false,不斷地往通道裏面放 product,完成之後信號量完成

func producer(wg *sync.WaitGroup, products chan<- Product, name int
, stop *bool) { for !*stop { product := Product{name: name, value: rand.Int()} products <- product fmt.Printf("producer %v produce a product: %#v\n", name, product) time.Sleep(time.Duration(200+rand.Intn(1000)) * time.Millisecond) } wg.Done() }

消費者

不斷地從通道裏面取 product,然後作對應的處理,直到通道被關閉,並且 products 裏面為空, for 循環才會終止,而這正是我們期望的

func consumer(wg *sync.WaitGroup, products <-chan Product, name int) {
    for product := range products {
        fmt.Printf("consumer %v consume a product: %#v\n", name, product)
        time.Sleep(time.Duration(200+rand.Intn(1000)) * time.Millisecond)
    }
    wg.Done()
}

主線程

var wgp sync.WaitGroup
var wgc sync.WaitGroup
stop := false
products := make(chan Product, 10)

// 創建 5 個生產者和 5 個消費者
for i := 0; i < 5; i++ {
    go producer(&wgp, products, i, &stop)
    go consumer(&wgc, products, i)
    wgp.Add(1)
    wgc.Add(1)
}

time.Sleep(time.Duration(1) * time.Second)
stop = true     // 設置生產者終止信號
wgp.Wait()      // 等待生產者退出
close(products) // 關閉通道
wgc.Wait()      // 等待消費者退出

轉載請註明出處
本文鏈接:http://hatlonely.github.io/2018/03/11/golang-%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B%E4%B9%8B%E7%94%9F%E4%BA%A7%E8%80%85%E6%B6%88%E8%B4%B9%E8%80%85/

golang 並發編程之生產者消費者