Prompts for GPT

avatar User

gopool.go package gopool

type Task func()

type GoPool struct { Workers []*Worker MaxWorkers int workerStack []int }

func NewGoPool(maxWorkers int) *GoPool { pool := &GoPool{ MaxWorkers: maxWorkers, Workers: make([]*Worker, maxWorkers), workerStack: make([]int, maxWorkers), } for i := 0; i < maxWorkers; i++ { worker := newWorker() pool.Workers[i] = worker pool.workerStack[i] = i worker.start(pool, i) } return pool }

func (p *GoPool) AddTask(task Task) { workerIndex := p.popWorker() p.Workers[workerIndex].TaskQueue <- task }

func (p *GoPool) Release() { for _, worker := range p.Workers { close(worker.TaskQueue) } }

func (p *GoPool) popWorker() int { workerIndex := p.workerStack[len(p.workerStack)-1] p.workerStack = p.workerStack[:len(p.workerStack)-1] return workerIndex }

func (p *GoPool) pushWorker(workerIndex int) { p.workerStack = append(p.workerStack, workerIndex) }

worker.go package gopool

type Worker struct { TaskQueue chan Task }

func newWorker() *Worker { return &Worker{ TaskQueue: make(chan Task, 1), } }

func (w *Worker) start(pool *GoPool, workerIndex int) { go func() { for task := range w.TaskQueue { if task != nil { task() } pool.pushWorker(workerIndex) } }() }

It seems that you haven't considered what the AddTask method should do when the workers are exhausted. Obviously, continuing to execute popWorker() will cause slice out of bounds. I think you can add a very large capacity Channel in GoPool to store tasks that can't be distributed to Worker in time, and then listen to this Channel in a separate goroutine, constantly trying to get idle Worker, and distribute the tasks in the Channel to idle workers.

avatar DevChat

Based on your feedback, I made some modifications to the code. Below is the modified code:

In the gopool.go file:

package gopool

import "time"

type Task func()

type GoPool struct {
    Workers    []*Worker
    MaxWorkers int
    workerStack []int
    taskQueue chan Task
}

func NewGoPool(maxWorkers int) *GoPool {
    pool := &GoPool{
        MaxWorkers: maxWorkers,
        Workers:    make([]*Worker, maxWorkers),
        workerStack: make([]int, maxWorkers),
        taskQueue: make(chan Task, 1e6),
    }
    for i := 0; i < maxWorkers; i++ {
        worker := newWorker()
        pool.Workers[i] = worker
        pool.workerStack[i] = i
        worker.start(pool, i)
    }
    go pool.dispatch()
    return pool
}

func (p *GoPool) AddTask(task Task) {
    p.taskQueue <- task
}

func (p *GoPool) Release() {
    close(p.taskQueue)
    for _, worker := range p.Workers {
        close(worker.TaskQueue)
    }
}

func (p *GoPool) popWorker() int {
    workerIndex := p.workerStack[len(p.workerStack)-1]
    p.workerStack = p.workerStack[:len(p.workerStack)-1]
    return workerIndex
}

func (p *GoPool) pushWorker(workerIndex int) {
    p.workerStack = append(p.workerStack, workerIndex)
}

func (p *GoPool) dispatch() {
    for task := range p.taskQueue {
        for len(p.workerStack) == 0 {
            time.Sleep(time.Millisecond)
        }
        workerIndex := p.popWorker()
        p.Workers[workerIndex].TaskQueue <- task
    }
}

In the worker.go file:

package gopool

type Worker struct {
    TaskQueue chan Task
}

func newWorker() *Worker {
    return &Worker{
        TaskQueue: make(chan Task, 1),
    }
}

func (w *Worker) start(pool *GoPool, workerIndex int) {
    go func() {
        for task := range w.TaskQueue {
            if task != nil {
                task()
            }
            pool.pushWorker(workerIndex)
        }
    }()
}

In this implementation, a taskQueue is added to the GoPool structure to store tasks that can't be distributed to Worker in time. A dispatch method is added to listen to the taskQueue in a separate goroutine and distribute tasks to idle Worker. The AddTask method now just adds tasks to the taskQueue.