grpool goroutine池詳解 | 協程管理

語言: CN / TW / HK

highlight: a11y-dark theme: smartblue


持續創作,加速成長!這是我參與「掘金日新計劃 · 6 月更文挑戰」的第9天,點選檢視活動詳情

前言

goroutine協程非常輕量級,這也是為什麼go支援高併發,但是goroutine頻繁建立銷燬對GC的壓力比較大。

grpool的作用就是複用goroutine,減少頻繁建立銷燬的效能消耗。

名詞概念

Pool: goroutine池,用於管理若干可複用的goroutine協程資源

Worker: 池物件中參與任務執行的goroutine,一個worker可以執行若干個job,直到佇列中再無等待的job

Job:新增到池物件的任務佇列中等待執行的任務,是一個func()方法,一個job同時只能被一個worker獲取並執行。

使用示例

使用預設的協程池,限制100個協程執行1000個任務

pool.Size() 獲得當前工作的協程數量

pool.Jobs() 獲得當前池中待處理的任務數量

```go package main

import ( "fmt" "github.com/gogf/gf/os/grpool" "github.com/gogf/gf/os/gtimer" "sync" "time" )

func main() { pool := grpool.New(100)

//新增1千個任務 for i := 0; i < 1000; i++ { _ = pool.Add(job) }

fmt.Println("worker:", pool.Size()) //當前工作的協程數量 fmt.Println("jobs:", pool.Jobs()) //當前池中待處理的任務數量

gtimer.SetInterval(time.Second, func() { fmt.Println("worker:", pool.Size()) //當前工作的協程數 fmt.Println("jobs:", pool.Jobs()) //當前池中待處理的任務數 })

//阻止程序結束 select {} }

//任務方法 func job() { time.Sleep(time.Second) } ```

列印結果

image.png

是不是灰常簡單~

踩坑之旅

一個簡單的場景,請使用協程列印0~9。

常犯的錯誤

大家看下面的程式碼有沒有問題,請預測一下列印結果。

go wg := sync.WaitGroup{} for i := 0; i < 9; i++ { wg.Add(1) go func() { fmt.Println(i) wg.Done() }() } wg.Wait()

不用著急看答案

.

.

.

猜一下列印結果是什麼

列印結果

image.png

分析原因

對於非同步執行緒/協程來講,函式進行非同步執行註冊時,該函式並未真正開始執行(註冊時只在goroutine的棧中儲存了變數i的記憶體地址),而一旦開始執行時函式才會去讀取變數i的值,而這個時候變數i的值已經自增到了9

正確寫法

go wg := sync.WaitGroup{} for i := 0; i < 9; i++ { wg.Add(1) go func(v int) { fmt.Println(v) wg.Done() }(i) } wg.Wait()

列印結果

image.png

使用grpool

使用grpool和使用go一樣,都需要把當前變數i的值賦值給一個不會改變的臨時變數,在函式中使用該臨時變數而不是直接使用變數i

錯誤程式碼

go wg := sync.WaitGroup{} for i := 0; i < 9; i++ { wg.Add(1) _ = grpool.Add(func() { fmt.Println(i) //列印結果都是9 wg.Done() }) } wg.Wait()

列印結果

image.png

正確程式碼

go wg := sync.WaitGroup{} for i := 0; i < 9; i++ { wg.Add(1) v := i //grpoll.add() 的引數只能是不帶引數的匿名函式 因此只能以設定臨時變數的方式賦值 _ = grpool.Add(func() { fmt.Println(v) wg.Done() }) } wg.Wait()

列印結果

image.png

總結

通過這篇文章我們瞭解到:grpool的作用就是複用goroutine,減少頻繁建立銷燬的效能消耗。

也瞭解到使用協程容易犯的錯誤,以及用臨時變數的方式來解決問題。

說句題外話:grpool的基礎概念:Pool、Worke、Job 和我之前設計的派單系統簡直一模一樣。

最後

感謝閱讀,歡迎大家三連:點贊、收藏、~~投幣~~(關注)!!!

8e95dac1fd0b2b1ff51c08757667c47a.gif