go協(xié)程池實(shí)現(xiàn)原理小結(jié)
在go語言編程中有一種池肯定避免不了,那就是-協(xié)程池,無論你是日常工作還是面試中面試官都無法避免協(xié)程池,掌握協(xié)程池你也就算是入門go的并發(fā)編程了,打一波廣告后面會有專門的文章來介紹如何在go中進(jìn)行并發(fā)編程。
協(xié)程本身也是一種資源,但是協(xié)程池有自己的特殊性,那是由協(xié)程池執(zhí)行任務(wù)的特殊性決定的,協(xié)程作為資源使用時其實(shí)是在消費(fèi)其他資源,也就是說必須向協(xié)程池提供一個統(tǒng)一的接口,所有需要協(xié)程池執(zhí)行的任務(wù)都需要實(shí)現(xiàn)該接口,然后被協(xié)程池統(tǒng)一調(diào)用。
這里我們就要求所有需要被協(xié)程執(zhí)行的函數(shù)都要實(shí)現(xiàn)Worker接口的Task方法
type Worker interface { Task() }
另外一個特殊的點(diǎn),在于go協(xié)程執(zhí)行時特別是用戶添加任務(wù)時最好能夠讓用戶能夠感知到協(xié)程池當(dāng)前的工作狀態(tài),因此這里采用無緩沖區(qū)的chan作為協(xié)程池任務(wù)傳遞工具,能直接根據(jù)向chan添加任務(wù)時的狀態(tài)感知到當(dāng)前協(xié)程池的工作狀態(tài)。這里采用最簡單的阻塞方式來實(shí)現(xiàn),當(dāng)協(xié)程池忙的情況下直接阻塞直到協(xié)程池空閑用戶才能將自己的任務(wù)添加到協(xié)程池的管道中進(jìn)行執(zhí)行。
go中使用協(xié)程進(jìn)行工作,因此會創(chuàng)建并使用協(xié)程池進(jìn)行工作非常的有必要,work 包的目的是展示如何使用無緩沖的通道來創(chuàng)建一個 goroutine 池,這些 goroutine 執(zhí)行并控制一組工作,讓其并發(fā)執(zhí)行。在這種情況下,使用無緩沖的通道要比隨意指定一個緩沖區(qū)大小的有緩沖的通道好,因?yàn)檫@個情況下既不需要一個工作隊(duì)列,也不需要一組 goroutine 配合執(zhí)work 包的目的是展示如何使用無緩沖的通道來創(chuàng)建一個 goroutine 池,這些 goroutine 執(zhí)行并控制一組工作,讓其并發(fā)執(zhí)行。在這種情況下,使用無緩沖的通道要比隨意指定一個緩沖區(qū)大小的有緩沖的通道好,因?yàn)檫@個情況下既不需要一個工作隊(duì)列,也不需要一組goroutine 配合執(zhí)
結(jié)構(gòu)體
協(xié)程池工作比較單一,就是調(diào)用指定的Task方法,另外因?yàn)榻o出任務(wù)時最好能立刻執(zhí)行或者不能立刻執(zhí)行需要讓用戶等待,因此協(xié)程池最好使用無緩沖的通道,這樣當(dāng)用戶需要執(zhí)行Task時就能直接從接口中感知到當(dāng)前協(xié)程池是否空閑了。
type Worker interface { Task() } type Pool struct { // 使用無緩沖通道實(shí)現(xiàn)協(xié)程池 work chan Worker // 輔助計(jì)數(shù)器,用于協(xié)程池同步 wg sync.WaitGroup }
創(chuàng)建協(xié)程池
創(chuàng)建協(xié)程池需要指定最大并發(fā)數(shù),當(dāng)有新的任務(wù)加入時,會立即被執(zhí)行,而當(dāng)沒有任務(wù)時,所有協(xié)程池中的協(xié)程阻塞競爭等待通道中的"任務(wù)"。
// New 創(chuàng)建一個工作池 func New(maxGoroutine int) *Pool { p := Pool{ work: make(chan Worker), } p.wg.Add(maxGoroutine) for i := 0; i < maxGoroutine; i++ { go func() { // 一直循環(huán)取任務(wù),直到work被關(guān)閉為止并且通道中的任務(wù)執(zhí)行完畢為止 for w := range p.work { w.Task() } // 退出時候,減少一個計(jì)數(shù)器 p.wg.Done() }() } return &p }
協(xié)程池啟動和關(guān)閉
觸發(fā)協(xié)程池工作很簡單,只需要向協(xié)程池等待的通道中放入一個任務(wù)即可,當(dāng)協(xié)程池關(guān)閉時,所有任務(wù)都會被立即執(zhí)行,當(dāng)所有任務(wù)執(zhí)行完畢,協(xié)程池中的所有協(xié)程都會退出。
// Run 將任務(wù)放入工作池 func (p *Pool) Run(w Worker) { p.work <- w } // Shutdown 等待所有g(shù)oroutine完成工作 func (p *Pool) Shutdown() { // 關(guān)閉work所有協(xié)程完成任務(wù)之后會退出for循環(huán) close(p.work) p.wg.Wait() }
將上述實(shí)現(xiàn)匯總之后如下
work/work.go
package work import "sync" // Worker interface 必須滿足worker的要求才能使用工作池 type Worker interface { Task() } // Pool 提供一個goroutine池,這個池可以完成任何已提交的woker任務(wù) type Pool struct { work chan Worker wg sync.WaitGroup } // New 創(chuàng)建一個工作池 func New(maxGoroutine int) *Pool { p := Pool{ work: make(chan Worker), } p.wg.Add(maxGoroutine) for i := 0; i < maxGoroutine; i++ { go func() { // 一直循環(huán)取任務(wù),直到work被關(guān)閉為止 for w := range p.work { w.Task() } // 退出時候,減少一個計(jì)數(shù)器 p.wg.Done() }() } return &p } // Run 將任務(wù)放入工作池 func (p *Pool) Run(w Worker) { p.work <- w } // Shutdown 等待所有g(shù)oroutine完成工作 func (p *Pool) Shutdown() { // 關(guān)閉work所有協(xié)程完成任務(wù)之后會退出for循環(huán) close(p.work) p.wg.Wait() }
對實(shí)現(xiàn)的接口進(jìn)行功能測試
// This sample program demonstrates how to use the work package // to use a pool of goroutines to get work done. package main import ( "log" "sync" "time" "work" ) // names provides a set of names to display. var names = []string{ "steve", "bob", "mary", "therese", "jason", } // namePrinter provides special support for printing names. type namePrinter struct { name string } // Task implements the Worker interface. func (m *namePrinter) Task() { log.Println(m.name) time.Sleep(time.Second) } // main is the entry point for all Go programs. func main() { // Create a work pool with 2 goroutines. p := work.New(2) var wg sync.WaitGroup wg.Add(100 * len(names)) for i := 0; i < 100; i++ { // Iterate over the slice of names. for _, name := range names { // Create a namePrinter and provide the // specific name. np := namePrinter{ name: name, } go func() { // Submit the task to be worked on. When RunTask // returns we know it is being handled. p.Run(&np) wg.Done() }() } } wg.Wait() // Shutdown the work pool and wait for all existing work // to be completed. p.Shutdown() }
到此這篇關(guān)于go協(xié)程池實(shí)現(xiàn)原理小結(jié)的文章就介紹到這了,更多相關(guān)go 協(xié)程池內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- golang協(xié)程池設(shè)計(jì)詳解
- golang協(xié)程池模擬實(shí)現(xiàn)群發(fā)郵件功能
- GO實(shí)現(xiàn)協(xié)程池管理的方法
- Golang協(xié)程池gopool設(shè)計(jì)與實(shí)現(xiàn)
- Go簡單實(shí)現(xiàn)協(xié)程池的實(shí)現(xiàn)示例
- Golang協(xié)程池的實(shí)現(xiàn)與應(yīng)用
- Go高級特性探究之協(xié)程池詳解
- 詳解Go語言如何實(shí)現(xiàn)一個最簡化的協(xié)程池
- Golang線程池與協(xié)程池的使用
- golang實(shí)現(xiàn)協(xié)程池的方法示例
相關(guān)文章
使用Go語言創(chuàng)建error的幾種方式小結(jié)
Go語言函數(shù)(或方法)是支持多個返回值的,因此在Go語言的編程哲學(xué)中,函數(shù)的返回值的最后一個通常都是error類型,所以本文給大家介紹了使用Go語言創(chuàng)建error的幾種方式小結(jié),文中通過代碼示例講解的非常詳細(xì),需要的朋友可以參考下2024-01-01詳解如何在Go中循環(huán)中使用Defer關(guān)鍵字示例詳解
這篇文章主要為大家介紹了詳解如何在Go中循環(huán)中使用Defer關(guān)鍵字示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09Golang設(shè)計(jì)模式中的橋接模式詳細(xì)講解
橋接模式是一種結(jié)構(gòu)型設(shè)計(jì)模式,通過橋接模式可以將抽象部分和它的實(shí)現(xiàn)部分分離,本文主要介紹了GoLang橋接模式,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2023-01-01Golang標(biāo)準(zhǔn)庫unsafe源碼解讀
這篇文章主要為大家介紹了Golang標(biāo)準(zhǔn)庫unsafe源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08Golang觀察者模式優(yōu)化訂單處理系統(tǒng)實(shí)例探究
當(dāng)涉及到訂單處理系統(tǒng)時,觀察者設(shè)計(jì)模式可以用于實(shí)現(xiàn)訂單狀態(tài)的變化和通知,在這篇文章中,我們將介紹如何使用Golang來實(shí)現(xiàn)觀察者設(shè)計(jì)模式,并提供一個基于訂單處理系統(tǒng)的代碼示例2024-01-01golang jwt鑒權(quán)的實(shí)現(xiàn)流程
本文主要介紹了golang jwt鑒權(quán)的實(shí)現(xiàn)流程,包含生成JWT令牌、客戶端存儲和發(fā)送JWT令牌、服務(wù)端驗(yàn)證JWT令牌等,具有一定的參考價(jià)值,感興趣的可以了解一下2025-02-02