Prompts for GPT
User
gopool.go
package gopooltype Task func()
type GoPool struct { TaskQueue chan Task MaxWorkers int Workers []*Worker }
func NewGoPool(maxWorkers int) *GoPool { pool := &GoPool{ TaskQueue: make(chan Task), MaxWorkers: maxWorkers, Workers: make([]*Worker, maxWorkers), } for i := 0; i < maxWorkers; i++ { worker := newWorker(pool.TaskQueue) pool.Workers[i] = worker worker.start() } return pool }
func (p *GoPool) AddTask(task Task) { p.TaskQueue <- task }
func (p *GoPool) Release() { close(p.TaskQueue) for _, worker := range p.Workers { <-worker.TaskQueue } }
worker.go
package gopooltype Worker struct { TaskQueue chan Task }
func newWorker(taskQueue chan Task) *Worker { return &Worker{ TaskQueue: taskQueue, } }
func (w *Worker) start() { go func() { for task := range w.TaskQueue { if task != nil { task() } } }() }
The performance test results are not satisfactory. I suspect it might be due to all workers consuming the same TaskQueue, which requires too many locks. Perhaps we can make the following modifications:
- Remove GoPool.TaskQueue. When AddTask is invoked, directly throw the Task into Worker.TaskQueue.
- Retain a Task Channel with a capacity of 1 in Worker.
- AddTask needs to retrieve an idle Worker from GoPool.Workers. After the Worker finishes processing the Task, it needs to be returned to GoPool. Therefore, you should consider implementing workers as a stack, adding corresponding push and pop methods.
DevChat
In accordance with your feedback, I have made some modifications to the code. Here is the modified code:
In the gopool.go file:
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)
}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, the TaskQueue in the GoPool struct has been removed, and each Worker has its own TaskQueue. The AddTask method will add tasks to the TaskQueue of an idle Worker. The Release method will close the TaskQueue of all Workers. The popWorker and pushWorker methods have been added for retrieving and returning Worker from the workerStack.