我已经实现了一个Golang员工池,如下所示,其中sem和work是渠道.SEM是跟踪当前活动的工作线程(Goroutine)数量的渠道.工作是将功能传递给活动工作人员执行的渠道.超时将返回任何在超时持续时间内处于空闲状态的工作进程.
package main
import (
"time"
)
type Pool struct {
sem chan struct{}
work chan func()
timeout time.Duration
}
func NewPool(max, size, spawn int, timeout time.Duration) *Pool {
if spawn <= 0 {
panic("workpool spawn is <= 0")
}
if spawn > max {
panic("workpool spawn > max workers")
}
p := &Pool{
sem: make(chan struct{}, max),
work: make(chan func(), size),
timeout: timeout,
}
for i := 0; i < spawn; i++ {
p.sem <- struct{}{}
go p.worker(func() {})
}
return p
}
func (p *Pool) AddTask(task func()) {
select {
case p.work <- task:
return
case p.sem <- struct{}{}:
go p.worker(task)
return
}
}
func (p *Pool) worker(task func()) {
t := time.NewTimer(p.timeout)
defer func() {
t.Stop()
<- p.sem
}()
task()
for {
select {
case task := <- p.work:
t.Reset(p.timeout)
task()
case <- t.C:
return
}
}
}
我通过在for循环中打印i的值进行测试,方法是将i的值传递到匿名函数中包装的池中,如下所示:
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println("Hello, world!")
p := NewPool(3, 10, 1, time.Duration(5) * time.Second)
for i:=0; i<30; i++ {
p.AddTask(func () {
fmt.Print(i, " ")
})
}
time.Sleep(10 * time.Second)
fmt.Println("End")
}
预期输出应为从0到29的序列号,但实际输出为
Hello, world!
12 12 12 12 12 12 12 12 12 12 12 12 13 25 25 25 25 25 25 25 25 25 25 25 26 25 30 30 30 30 End
我不明白为什么输出是这样的.