Returns -1 from Free() by unlimited pool

Fixes #152
This commit is contained in:
Andy Pan 2021-04-27 08:14:28 +08:00
parent dbcb6a104f
commit a2ad870d2d
3 changed files with 53 additions and 14 deletions

View File

@ -548,12 +548,42 @@ func TestInfinitePool(t *testing.T) {
if n := p.Running(); n != 2 { if n := p.Running(); n != 2 {
t.Errorf("expect 2 workers running, but got %d", n) t.Errorf("expect 2 workers running, but got %d", n)
} }
if n := p.Free(); n != -1 {
t.Errorf("expect -1 of free workers by unlimited pool, but got %d", n)
}
p.Tune(10) p.Tune(10)
if capacity := p.Cap(); capacity != -1 { if capacity := p.Cap(); capacity != -1 {
t.Fatalf("expect capacity: -1 but got %d", capacity) t.Fatalf("expect capacity: -1 but got %d", capacity)
} }
var err error var err error
p, err = NewPool(-1, WithPreAlloc(true)) _, err = NewPool(-1, WithPreAlloc(true))
if err != ErrInvalidPreAllocSize {
t.Errorf("expect ErrInvalidPreAllocSize but got %v", err)
}
}
func TestInfinitePoolWithFunc(t *testing.T) {
c := make(chan struct{})
p, _ := NewPoolWithFunc(-1, func(i interface{}) {
demoPoolFunc(i)
<-c
})
_ = p.Invoke(10)
_ = p.Invoke(10)
c <- struct{}{}
c <- struct{}{}
if n := p.Running(); n != 2 {
t.Errorf("expect 2 workers running, but got %d", n)
}
if n := p.Free(); n != -1 {
t.Errorf("expect -1 of free workers by unlimited pool, but got %d", n)
}
p.Tune(10)
if capacity := p.Cap(); capacity != -1 {
t.Fatalf("expect capacity: -1 but got %d", capacity)
}
var err error
_, err = NewPoolWithFunc(-1, demoPoolFunc, WithPreAlloc(true))
if err != ErrInvalidPreAllocSize { if err != ErrInvalidPreAllocSize {
t.Errorf("expect ErrInvalidPreAllocSize but got %v", err) t.Errorf("expect ErrInvalidPreAllocSize but got %v", err)
} }

13
pool.go
View File

@ -159,9 +159,13 @@ func (p *Pool) Running() int {
return int(atomic.LoadInt32(&p.running)) return int(atomic.LoadInt32(&p.running))
} }
// Free returns the available goroutines to work. // Free returns the available goroutines to work, -1 indicates this pool is unlimited.
func (p *Pool) Free() int { func (p *Pool) Free() int {
return p.Cap() - p.Running() c := p.Cap()
if c < 0 {
return -1
}
return c - p.Running()
} }
// Cap returns the capacity of this pool. // Cap returns the capacity of this pool.
@ -224,10 +228,7 @@ func (p *Pool) retrieveWorker() (w *goWorker) {
w = p.workers.detach() w = p.workers.detach()
if w != nil { if w != nil {
p.lock.Unlock() p.lock.Unlock()
} else if capacity := p.Cap(); capacity == -1 { } else if capacity := p.Cap(); capacity == -1 || capacity > p.Running() {
p.lock.Unlock()
spawnWorker()
} else if p.Running() < capacity {
p.lock.Unlock() p.lock.Unlock()
spawnWorker() spawnWorker()
} else { } else {

View File

@ -111,7 +111,7 @@ func (p *PoolWithFunc) purgePeriodically() {
// NewPoolWithFunc generates an instance of ants pool with a specific function. // NewPoolWithFunc generates an instance of ants pool with a specific function.
func NewPoolWithFunc(size int, pf func(interface{}), options ...Option) (*PoolWithFunc, error) { func NewPoolWithFunc(size int, pf func(interface{}), options ...Option) (*PoolWithFunc, error) {
if size <= 0 { if size <= 0 {
return nil, ErrInvalidPoolSize size = -1
} }
if pf == nil { if pf == nil {
@ -143,6 +143,9 @@ func NewPoolWithFunc(size int, pf func(interface{}), options ...Option) (*PoolWi
} }
} }
if p.options.PreAlloc { if p.options.PreAlloc {
if size == -1 {
return nil, ErrInvalidPreAllocSize
}
p.workers = make([]*goWorkerWithFunc, 0, size) p.workers = make([]*goWorkerWithFunc, 0, size)
} }
p.cond = sync.NewCond(p.lock) p.cond = sync.NewCond(p.lock)
@ -173,9 +176,13 @@ func (p *PoolWithFunc) Running() int {
return int(atomic.LoadInt32(&p.running)) return int(atomic.LoadInt32(&p.running))
} }
// Free returns a available goroutines to work. // Free returns a available goroutines to work, -1 indicates this pool is unlimited.
func (p *PoolWithFunc) Free() int { func (p *PoolWithFunc) Free() int {
return p.Cap() - p.Running() c := p.Cap()
if c < 0 {
return -1
}
return c - p.Running()
} }
// Cap returns the capacity of this pool. // Cap returns the capacity of this pool.
@ -185,7 +192,7 @@ func (p *PoolWithFunc) Cap() int {
// Tune changes the capacity of this pool. // Tune changes the capacity of this pool.
func (p *PoolWithFunc) Tune(size int) { func (p *PoolWithFunc) Tune(size int) {
if size <= 0 || size == p.Cap() || p.options.PreAlloc { if capacity := p.Cap(); capacity == -1 || size <= 0 || size == capacity || p.options.PreAlloc {
return return
} }
atomic.StoreInt32(&p.capacity, int32(size)) atomic.StoreInt32(&p.capacity, int32(size))
@ -245,7 +252,7 @@ func (p *PoolWithFunc) retrieveWorker() (w *goWorkerWithFunc) {
idleWorkers[n] = nil idleWorkers[n] = nil
p.workers = idleWorkers[:n] p.workers = idleWorkers[:n]
p.lock.Unlock() p.lock.Unlock()
} else if p.Running() < p.Cap() { } else if capacity := p.Cap(); capacity == -1 || capacity > p.Running() {
p.lock.Unlock() p.lock.Unlock()
spawnWorker() spawnWorker()
} else { } else {
@ -261,7 +268,8 @@ func (p *PoolWithFunc) retrieveWorker() (w *goWorkerWithFunc) {
p.blockingNum++ p.blockingNum++
p.cond.Wait() p.cond.Wait()
p.blockingNum-- p.blockingNum--
if p.Running() == 0 { var nw int
if nw = p.Running(); nw == 0 {
p.lock.Unlock() p.lock.Unlock()
if !p.IsClosed() { if !p.IsClosed() {
spawnWorker() spawnWorker()
@ -270,7 +278,7 @@ func (p *PoolWithFunc) retrieveWorker() (w *goWorkerWithFunc) {
} }
l := len(p.workers) - 1 l := len(p.workers) - 1
if l < 0 { if l < 0 {
if p.Running() < p.Cap() { if nw < capacity {
p.lock.Unlock() p.lock.Unlock()
spawnWorker() spawnWorker()
return return