Golangのゴルーチンプールの実装と活用方法
Golangでは、ゴルーチンとチャネルを使用して、ゴルーチンプールを実装することができます。以下は、タスクの処理にゴルーチンプールを使用する方法を示す簡単な例です。
package main
import (
"fmt"
"sync"
)
type Worker struct {
ID int
Task chan int
Done chan bool
WorkerPool chan chan int
}
func NewWorker(id int, workerPool chan chan int) *Worker {
return &Worker{
ID: id,
Task: make(chan int),
Done: make(chan bool),
WorkerPool: workerPool,
}
}
func (w *Worker) Start() {
go func() {
for {
// 把自己的任务通道注册到工作池
w.WorkerPool <- w.Task
select {
case task := <-w.Task:
// 处理任务
fmt.Printf("Worker %d processing task %d\n", w.ID, task)
case <-w.Done:
// 任务完成
fmt.Printf("Worker %d stopping\n", w.ID)
return
}
}
}()
}
func (w *Worker) Stop() {
go func() {
w.Done <- true
}()
}
type Pool struct {
WorkerPool chan chan int
Tasks chan int
MaxWorkers int
WaitGroup sync.WaitGroup
}
func NewPool(maxWorkers, maxTasks int) *Pool {
return &Pool{
WorkerPool: make(chan chan int, maxWorkers),
Tasks: make(chan int, maxTasks),
MaxWorkers: maxWorkers,
}
}
func (p *Pool) Start() {
// 启动协程池中的工作协程
for i := 0; i < p.MaxWorkers; i++ {
worker := NewWorker(i, p.WorkerPool)
worker.Start()
}
go p.dispatch()
}
func (p *Pool) dispatch() {
for {
select {
case task := <-p.Tasks:
workerTask := <-p.WorkerPool
// 分发任务给空闲的工作协程
workerTask <- task
}
}
}
func main() {
pool := NewPool(3, 10)
pool.Start()
// 添加任务到任务队列
for i := 0; i < 10; i++ {
pool.Tasks <- i
}
pool.WaitGroup.Wait()
}
上記の例では、Worker構造体が定義されており、その中にはタスクチャネルであるTaskと完了チャネルであるDoneが含まれています。Workerが起動すると、自分のタスクチャネルをワーカープールに登録し、タスクが到着するのを待ちます。タスクが到着すると、タスクチャネルからタスクを受け取り、処理します。タスクが完了すると、完了チャンネルを通じてメインスレッドに通知します。
プール構造体は、ワーカープールとタスクチャネルを含んでいます。Startメソッドでは、maxWorkers個のワーカーコルーチンを作成し、起動します。同時に、タスクチャネルからタスクを受け取り、空いているワーカーコルーチンに割り当てるdispatchコルーチンも起動します。
main関数では、コルーチンプールを作成し、タスクチャンネルに10個のタスクを追加しました。最後に、WaitGroupを使用してすべてのタスクが完了するのを待ちます。
これは、シンプルなGolangのゴルーチンプールの実装と利用例です。必要に応じて拡張や変更を行うことができます。