go協(xié)程池實現(xiàn)原理小結
在go語言編程中有一種池肯定避免不了,那就是-協(xié)程池,無論你是日常工作還是面試中面試官都無法避免協(xié)程池,掌握協(xié)程池你也就算是入門go的并發(fā)編程了,打一波廣告后面會有專門的文章來介紹如何在go中進行并發(fā)編程。
協(xié)程本身也是一種資源,但是協(xié)程池有自己的特殊性,那是由協(xié)程池執(zhí)行任務的特殊性決定的,協(xié)程作為資源使用時其實是在消費其他資源,也就是說必須向協(xié)程池提供一個統(tǒng)一的接口,所有需要協(xié)程池執(zhí)行的任務都需要實現(xiàn)該接口,然后被協(xié)程池統(tǒng)一調(diào)用。
這里我們就要求所有需要被協(xié)程執(zhí)行的函數(shù)都要實現(xiàn)Worker接口的Task方法
type Worker interface {
Task()
}
另外一個特殊的點,在于go協(xié)程執(zhí)行時特別是用戶添加任務時最好能夠讓用戶能夠感知到協(xié)程池當前的工作狀態(tài),因此這里采用無緩沖區(qū)的chan作為協(xié)程池任務傳遞工具,能直接根據(jù)向chan添加任務時的狀態(tài)感知到當前協(xié)程池的工作狀態(tài)。這里采用最簡單的阻塞方式來實現(xiàn),當協(xié)程池忙的情況下直接阻塞直到協(xié)程池空閑用戶才能將自己的任務添加到協(xié)程池的管道中進行執(zhí)行。

go中使用協(xié)程進行工作,因此會創(chuàng)建并使用協(xié)程池進行工作非常的有必要,work 包的目的是展示如何使用無緩沖的通道來創(chuàng)建一個 goroutine 池,這些 goroutine 執(zhí)行并控制一組工作,讓其并發(fā)執(zhí)行。在這種情況下,使用無緩沖的通道要比隨意指定一個緩沖區(qū)大小的有緩沖的通道好,因為這個情況下既不需要一個工作隊列,也不需要一組 goroutine 配合執(zhí)work 包的目的是展示如何使用無緩沖的通道來創(chuàng)建一個 goroutine 池,這些 goroutine 執(zhí)行并控制一組工作,讓其并發(fā)執(zhí)行。在這種情況下,使用無緩沖的通道要比隨意指定一個緩沖區(qū)大小的有緩沖的通道好,因為這個情況下既不需要一個工作隊列,也不需要一組goroutine 配合執(zhí)
結構體
協(xié)程池工作比較單一,就是調(diào)用指定的Task方法,另外因為給出任務時最好能立刻執(zhí)行或者不能立刻執(zhí)行需要讓用戶等待,因此協(xié)程池最好使用無緩沖的通道,這樣當用戶需要執(zhí)行Task時就能直接從接口中感知到當前協(xié)程池是否空閑了。
type Worker interface {
Task()
}
type Pool struct {
// 使用無緩沖通道實現(xiàn)協(xié)程池
work chan Worker
// 輔助計數(shù)器,用于協(xié)程池同步
wg sync.WaitGroup
}
創(chuàng)建協(xié)程池
創(chuàng)建協(xié)程池需要指定最大并發(fā)數(shù),當有新的任務加入時,會立即被執(zhí)行,而當沒有任務時,所有協(xié)程池中的協(xié)程阻塞競爭等待通道中的"任務"。
// 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)取任務,直到work被關閉為止并且通道中的任務執(zhí)行完畢為止
for w := range p.work {
w.Task()
}
// 退出時候,減少一個計數(shù)器
p.wg.Done()
}()
}
return &p
}
協(xié)程池啟動和關閉
觸發(fā)協(xié)程池工作很簡單,只需要向協(xié)程池等待的通道中放入一個任務即可,當協(xié)程池關閉時,所有任務都會被立即執(zhí)行,當所有任務執(zhí)行完畢,協(xié)程池中的所有協(xié)程都會退出。
// Run 將任務放入工作池
func (p *Pool) Run(w Worker) {
p.work <- w
}
// Shutdown 等待所有goroutine完成工作
func (p *Pool) Shutdown() {
// 關閉work所有協(xié)程完成任務之后會退出for循環(huán)
close(p.work)
p.wg.Wait()
}
將上述實現(xiàn)匯總之后如下
work/work.go
package work
import "sync"
// Worker interface 必須滿足worker的要求才能使用工作池
type Worker interface {
Task()
}
// Pool 提供一個goroutine池,這個池可以完成任何已提交的woker任務
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)取任務,直到work被關閉為止
for w := range p.work {
w.Task()
}
// 退出時候,減少一個計數(shù)器
p.wg.Done()
}()
}
return &p
}
// Run 將任務放入工作池
func (p *Pool) Run(w Worker) {
p.work <- w
}
// Shutdown 等待所有goroutine完成工作
func (p *Pool) Shutdown() {
// 關閉work所有協(xié)程完成任務之后會退出for循環(huán)
close(p.work)
p.wg.Wait()
}
對實現(xià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()
}
到此這篇關于go協(xié)程池實現(xiàn)原理小結的文章就介紹到這了,更多相關go 協(xié)程池內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
詳解如何在Go中循環(huán)中使用Defer關鍵字示例詳解
這篇文章主要為大家介紹了詳解如何在Go中循環(huán)中使用Defer關鍵字示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-09-09
Golang觀察者模式優(yōu)化訂單處理系統(tǒng)實例探究
當涉及到訂單處理系統(tǒng)時,觀察者設計模式可以用于實現(xiàn)訂單狀態(tài)的變化和通知,在這篇文章中,我們將介紹如何使用Golang來實現(xiàn)觀察者設計模式,并提供一個基于訂單處理系統(tǒng)的代碼示例2024-01-01

