go協(xié)程池實(shí)現(xiàn)原理小結(jié)
在go語(yǔ)言編程中有一種池肯定避免不了,那就是-協(xié)程池,無(wú)論你是日常工作還是面試中面試官都無(wú)法避免協(xié)程池,掌握協(xié)程池你也就算是入門(mén)go的并發(fā)編程了,打一波廣告后面會(huì)有專(zhuān)門(mén)的文章來(lái)介紹如何在go中進(jìn)行并發(fā)編程。
協(xié)程本身也是一種資源,但是協(xié)程池有自己的特殊性,那是由協(xié)程池執(zhí)行任務(wù)的特殊性決定的,協(xié)程作為資源使用時(shí)其實(shí)是在消費(fèi)其他資源,也就是說(shuō)必須向協(xié)程池提供一個(gè)統(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()
}
另外一個(gè)特殊的點(diǎn),在于go協(xié)程執(zhí)行時(shí)特別是用戶添加任務(wù)時(shí)最好能夠讓用戶能夠感知到協(xié)程池當(dāng)前的工作狀態(tài),因此這里采用無(wú)緩沖區(qū)的chan作為協(xié)程池任務(wù)傳遞工具,能直接根據(jù)向chan添加任務(wù)時(shí)的狀態(tài)感知到當(dāng)前協(xié)程池的工作狀態(tài)。這里采用最簡(jiǎn)單的阻塞方式來(lái)實(shí)現(xiàn),當(dāng)協(xié)程池忙的情況下直接阻塞直到協(xié)程池空閑用戶才能將自己的任務(wù)添加到協(xié)程池的管道中進(jìn)行執(zhí)行。

go中使用協(xié)程進(jìn)行工作,因此會(huì)創(chuàng)建并使用協(xié)程池進(jìn)行工作非常的有必要,work 包的目的是展示如何使用無(wú)緩沖的通道來(lái)創(chuàng)建一個(gè) goroutine 池,這些 goroutine 執(zhí)行并控制一組工作,讓其并發(fā)執(zhí)行。在這種情況下,使用無(wú)緩沖的通道要比隨意指定一個(gè)緩沖區(qū)大小的有緩沖的通道好,因?yàn)檫@個(gè)情況下既不需要一個(gè)工作隊(duì)列,也不需要一組 goroutine 配合執(zhí)work 包的目的是展示如何使用無(wú)緩沖的通道來(lái)創(chuàng)建一個(gè) goroutine 池,這些 goroutine 執(zhí)行并控制一組工作,讓其并發(fā)執(zhí)行。在這種情況下,使用無(wú)緩沖的通道要比隨意指定一個(gè)緩沖區(qū)大小的有緩沖的通道好,因?yàn)檫@個(gè)情況下既不需要一個(gè)工作隊(duì)列,也不需要一組goroutine 配合執(zhí)
結(jié)構(gòu)體
協(xié)程池工作比較單一,就是調(diào)用指定的Task方法,另外因?yàn)榻o出任務(wù)時(shí)最好能立刻執(zhí)行或者不能立刻執(zhí)行需要讓用戶等待,因此協(xié)程池最好使用無(wú)緩沖的通道,這樣當(dāng)用戶需要執(zhí)行Task時(shí)就能直接從接口中感知到當(dāng)前協(xié)程池是否空閑了。
type Worker interface {
Task()
}
type Pool struct {
// 使用無(wú)緩沖通道實(shí)現(xiàn)協(xié)程池
work chan Worker
// 輔助計(jì)數(shù)器,用于協(xié)程池同步
wg sync.WaitGroup
}
創(chuàng)建協(xié)程池
創(chuàng)建協(xié)程池需要指定最大并發(fā)數(shù),當(dāng)有新的任務(wù)加入時(shí),會(huì)立即被執(zhí)行,而當(dāng)沒(méi)有任務(wù)時(shí),所有協(xié)程池中的協(xié)程阻塞競(jìng)爭(zhēng)等待通道中的"任務(wù)"。
// New 創(chuàng)建一個(gè)工作池
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()
}
// 退出時(shí)候,減少一個(gè)計(jì)數(shù)器
p.wg.Done()
}()
}
return &p
}
協(xié)程池啟動(dòng)和關(guān)閉
觸發(fā)協(xié)程池工作很簡(jiǎn)單,只需要向協(xié)程池等待的通道中放入一個(gè)任務(wù)即可,當(dāng)協(xié)程池關(guān)閉時(shí),所有任務(wù)都會(huì)被立即執(zhí)行,當(dāng)所有任務(wù)執(zhí)行完畢,協(xié)程池中的所有協(xié)程都會(huì)退出。
// Run 將任務(wù)放入工作池
func (p *Pool) Run(w Worker) {
p.work <- w
}
// Shutdown 等待所有g(shù)oroutine完成工作
func (p *Pool) Shutdown() {
// 關(guān)閉work所有協(xié)程完成任務(wù)之后會(huì)退出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 提供一個(gè)goroutine池,這個(gè)池可以完成任何已提交的woker任務(wù)
type Pool struct {
work chan Worker
wg sync.WaitGroup
}
// New 創(chuàng)建一個(gè)工作池
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()
}
// 退出時(shí)候,減少一個(gè)計(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ù)之后會(huì)退出for循環(huán)
close(p.work)
p.wg.Wait()
}
對(duì)實(shí)現(xiàn)的接口進(jìn)行功能測(cè)試
// 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)容請(qǐng)搜索腳本之家以前的文章或繼續(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簡(jiǎn)單實(shí)現(xiàn)協(xié)程池的實(shí)現(xiàn)示例
- Golang協(xié)程池的實(shí)現(xiàn)與應(yīng)用
- Go高級(jí)特性探究之協(xié)程池詳解
- 詳解Go語(yǔ)言如何實(shí)現(xiàn)一個(gè)最簡(jiǎn)化的協(xié)程池
- Golang線程池與協(xié)程池的使用
- golang實(shí)現(xiàn)協(xié)程池的方法示例
相關(guān)文章
使用Go語(yǔ)言創(chuàng)建error的幾種方式小結(jié)
Go語(yǔ)言函數(shù)(或方法)是支持多個(gè)返回值的,因此在Go語(yǔ)言的編程哲學(xué)中,函數(shù)的返回值的最后一個(gè)通常都是error類(lèi)型,所以本文給大家介紹了使用Go語(yǔ)言創(chuàng)建error的幾種方式小結(jié),文中通過(guò)代碼示例講解的非常詳細(xì),需要的朋友可以參考下2024-01-01
詳解如何在Go中循環(huán)中使用Defer關(guān)鍵字示例詳解
這篇文章主要為大家介紹了詳解如何在Go中循環(huán)中使用Defer關(guān)鍵字示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09
go語(yǔ)言入門(mén)環(huán)境搭建及GoLand安裝教程詳解
這篇文章主要介紹了go語(yǔ)言入門(mén)環(huán)境搭建及GoLand安裝教程詳解,需要的朋友可以參考下2020-12-12
Golang設(shè)計(jì)模式中的橋接模式詳細(xì)講解
橋接模式是一種結(jié)構(gòu)型設(shè)計(jì)模式,通過(guò)橋接模式可以將抽象部分和它的實(shí)現(xiàn)部分分離,本文主要介紹了GoLang橋接模式,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2023-01-01
Golang標(biāo)準(zhǔn)庫(kù)unsafe源碼解讀
這篇文章主要為大家介紹了Golang標(biāo)準(zhǔn)庫(kù)unsafe源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08
Golang觀察者模式優(yōu)化訂單處理系統(tǒng)實(shí)例探究
當(dāng)涉及到訂單處理系統(tǒng)時(shí),觀察者設(shè)計(jì)模式可以用于實(shí)現(xiàn)訂單狀態(tài)的變化和通知,在這篇文章中,我們將介紹如何使用Golang來(lái)實(shí)現(xiàn)觀察者設(shè)計(jì)模式,并提供一個(gè)基于訂單處理系統(tǒng)的代碼示例2024-01-01
golang jwt鑒權(quán)的實(shí)現(xiàn)流程
本文主要介紹了golang jwt鑒權(quán)的實(shí)現(xiàn)流程,包含生成JWT令牌、客戶端存儲(chǔ)和發(fā)送JWT令牌、服務(wù)端驗(yàn)證JWT令牌等,具有一定的參考價(jià)值,感興趣的可以了解一下2025-02-02

