golangどのようにスレッドプールを実装するか
Go言語では、goroutineやチャネルを用いることでスレッドプールの機能を実現できます。以下に簡単な例を示します。
package main
import (
"fmt"
"sync"
)
type Job struct {
id int
}
type Worker struct {
id int
jobChannel chan Job
quit chan bool
}
func NewWorker(id int, jobChannel chan Job) *Worker {
return &Worker{
id: id,
jobChannel: jobChannel,
quit: make(chan bool),
}
}
func (w *Worker) Start(wg *sync.WaitGroup) {
go func() {
defer wg.Done()
for {
select {
case job := <-w.jobChannel:
fmt.Printf("Worker %d started job %d\n", w.id, job.id)
// 模拟处理任务
// time.Sleep(time.Second)
fmt.Printf("Worker %d finished job %d\n", w.id, job.id)
case <-w.quit:
return
}
}
}()
}
func (w *Worker) Stop() {
go func() {
w.quit <- true
}()
}
type Pool struct {
jobChannel chan Job
workers []*Worker
wg sync.WaitGroup
}
func NewPool(numWorkers, maxJobs int) *Pool {
jobChannel := make(chan Job, maxJobs)
workers := make([]*Worker, numWorkers)
for i := 0; i < numWorkers; i++ {
workers[i] = NewWorker(i+1, jobChannel)
}
return &Pool{
jobChannel: jobChannel,
workers: workers,
}
}
func (p *Pool) Start() {
for _, worker := range p.workers {
worker.Start(&p.wg)
p.wg.Add(1)
}
}
func (p *Pool) AddJob(job Job) {
p.jobChannel <- job
}
func (p *Pool) Stop() {
for _, worker := range p.workers {
worker.Stop()
}
p.wg.Wait()
close(p.jobChannel)
}
func main() {
pool := NewPool(3, 10)
pool.Start()
for i := 0; i < 10; i++ {
pool.AddJob(Job{id: i + 1})
}
pool.Stop()
}
上記サンプルでは、Job構造体は実行する必要があるタスクを表し、Worker構造体はスレッドプールのワーカーゴルーチンを表します。Pool構造体はスレッドプールを表し、タスクへのチャネルと複数のワーカーゴルーチンを持ちます。
PoolのStartメソッドでは、各ワーカーを1つの独立したゴルーチンで起動し、ワーカーゴルーチンがタスクを完了するのを待って完了させます。
タスクをタスクチャンネルに追加すると、ワーカーがチャンネルからタスクを取得して実行します。
最後に、main 関数でスレッドプールを作成し、スレッドプールに 10 のタスクを追加します。その後、スレッドプールの Stop メソッドを呼び出し、タスクの実行が完了するまで待機します。
上記の例では、タスクは単に情報を印刷していることに注意してください。実際にはタスクの実行ロジックは、あなたのニーズに基づいて変更できます。