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のゴルーチンプールの実装と利用例です。必要に応じて拡張や変更を行うことができます。

bannerAds