grpool?goroutine池協(xié)程管理
前言
goroutine協(xié)程非常輕量級(jí),這也是為什么go支持高并發(fā),但是goroutine頻繁創(chuàng)建銷毀對(duì)GC的壓力比較大。
grpool的作用就是復(fù)用goroutine,減少頻繁創(chuàng)建銷毀的性能消耗。
名詞概念
Pool: goroutine池,用于管理若干可復(fù)用的goroutine協(xié)程資源
Worker: 池對(duì)象中參與任務(wù)執(zhí)行的goroutine,一個(gè)worker可以執(zhí)行若干個(gè)job,直到隊(duì)列中再無(wú)等待的job
Job:添加到池對(duì)象的任務(wù)隊(duì)列中等待執(zhí)行的任務(wù),是一個(gè)func()方法,一個(gè)job同時(shí)只能被一個(gè)worker獲取并執(zhí)行。
使用示例
使用默認(rèn)的協(xié)程池,限制100個(gè)協(xié)程執(zhí)行1000個(gè)任務(wù)
pool.Size() 獲得當(dāng)前工作的協(xié)程數(shù)量
pool.Jobs() 獲得當(dāng)前池中待處理的任務(wù)數(shù)量
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千個(gè)任務(wù)
for i := 0; i < 1000; i++ {
_ = pool.Add(job)
}
fmt.Println("worker:", pool.Size()) //當(dāng)前工作的協(xié)程數(shù)量
fmt.Println("jobs:", pool.Jobs()) //當(dāng)前池中待處理的任務(wù)數(shù)量
gtimer.SetInterval(time.Second, func() {
fmt.Println("worker:", pool.Size()) //當(dāng)前工作的協(xié)程數(shù)
fmt.Println("jobs:", pool.Jobs()) //當(dāng)前池中待處理的任務(wù)數(shù)
})
//阻止進(jìn)程結(jié)束
select {}
}
//任務(wù)方法
func job() {
time.Sleep(time.Second)
}打印結(jié)果:

是不是灰常簡(jiǎn)單~
踩坑之旅
一個(gè)簡(jiǎn)單的場(chǎng)景,請(qǐng)使用協(xié)程打印0~9。
常犯的錯(cuò)誤
大家看下面的代碼有沒(méi)有問(wèn)題,請(qǐng)預(yù)測(cè)一下打印結(jié)果。
wg := sync.WaitGroup{}
for i := 0; i < 9; i++ {
wg.Add(1)
go func() {
fmt.Println(i)
wg.Done()
}()
}
wg.Wait()不用著急看答案
猜一下打印結(jié)果是什么
打印結(jié)果:

分析原因
對(duì)于異步線程/協(xié)程來(lái)講,函數(shù)進(jìn)行異步執(zhí)行注冊(cè)時(shí),該函數(shù)并未真正開始執(zhí)行(注冊(cè)時(shí)只在goroutine的棧中保存了變量i的內(nèi)存地址),而一旦開始執(zhí)行時(shí)函數(shù)才會(huì)去讀取變量i的值,而這個(gè)時(shí)候變量i的值已經(jīng)自增到了9。
正確寫法:
wg := sync.WaitGroup{}
for i := 0; i < 9; i++ {
wg.Add(1)
go func(v int) {
fmt.Println(v)
wg.Done()
}(i)
}
wg.Wait()打印結(jié)果:

使用grpool
使用grpool和使用go一樣,都需要把當(dāng)前變量i的值賦值給一個(gè)不會(huì)改變的臨時(shí)變量,在函數(shù)中使用該臨時(shí)變量而不是直接使用變量i。
錯(cuò)誤代碼
wg := sync.WaitGroup{}
for i := 0; i < 9; i++ {
wg.Add(1)
_ = grpool.Add(func() {
fmt.Println(i) //打印結(jié)果都是9
wg.Done()
})
}
wg.Wait()打印結(jié)果:

正確代碼
wg := sync.WaitGroup{}
for i := 0; i < 9; i++ {
wg.Add(1)
v := i //grpoll.add() 的參數(shù)只能是不帶參數(shù)的匿名函數(shù) 因此只能以設(shè)置臨時(shí)變量的方式賦值
_ = grpool.Add(func() {
fmt.Println(v)
wg.Done()
})
}
wg.Wait()打印結(jié)果:

總結(jié)
通過(guò)這篇文章我們了解到:grpool的作用就是復(fù)用goroutine,減少頻繁創(chuàng)建銷毀的性能消耗。也了解到使用協(xié)程容易犯的錯(cuò)誤,以及用臨時(shí)變量的方式來(lái)解決問(wèn)題。
說(shuō)句題外話:grpool的基礎(chǔ)概念:Pool、Worke、Job 和我之前設(shè)計(jì)的派單系統(tǒng)簡(jiǎn)直一模一樣。
到此這篇關(guān)于grpool goroutine池協(xié)程管理的文章就介紹到這了,更多相關(guān)grpool goroutine池 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
golang時(shí)間及時(shí)間戳的獲取轉(zhuǎn)換
本文主要介紹了golang時(shí)間及時(shí)間戳的獲取轉(zhuǎn)換,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06
Golang Map實(shí)現(xiàn)賦值和擴(kuò)容的示例代碼
這篇文章主要介紹了Golang Map實(shí)現(xiàn)賦值和擴(kuò)容的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04
golang敏感詞過(guò)濾的實(shí)現(xiàn)
本文主要介紹了golang敏感詞過(guò)濾的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01
Goland IDEA項(xiàng)目多開設(shè)置方式
這篇文章主要介紹了Goland IDEA項(xiàng)目多開設(shè)置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12
golang接口實(shí)現(xiàn)調(diào)用修改(值接收者指針接收者)場(chǎng)景詳解
這篇文章主要為大家介紹了golang接口實(shí)現(xiàn)調(diào)用修改值接收者指針接收者示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08
go代碼實(shí)現(xiàn)買房貸款月供計(jì)算的方法
今天小編就為大家分享一篇關(guān)于go代碼實(shí)現(xiàn)買房貸款月供計(jì)算的方法,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-04-04
Fedora14 Linux系統(tǒng)安裝Golang開發(fā)環(huán)境筆記
這篇文章主要介紹了Fedora14 Linux系統(tǒng)安裝Golang開發(fā)環(huán)境筆記,本文講解了2種安裝方法,需要的朋友可以參考下2014-10-10

