Skip to content

Commit 8e5ba59

Browse files
authored
always spawn a worker with the task it was supposed to complete (#112)
For "unlimited" pools, in the original code: ```go p.handle.Go(p.worker) p.tasks <- f ``` If in between the call to `handle.Go` and sending the task to the worker, another goroutine would call `pool.Go`, that task would "hijack" the newly created worker, causing the original send to block. This is undesirable behavior if the pool is unlimited. The solution was to add an `initialFunc` to the worker, which will be executed before the worker starts waiting for new tasks. This ensures that a worker will first complete the task it was supposed to, then complete others.
1 parent 06d3061 commit 8e5ba59

1 file changed

Lines changed: 11 additions & 9 deletions

File tree

pool/pool.go

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,20 +47,18 @@ func (p *Pool) Go(f func()) {
4747
default:
4848
// No goroutine was available to handle the task.
4949
// Spawn a new one and send it the task.
50-
p.handle.Go(p.worker)
51-
p.tasks <- f
50+
p.handle.Go(func() {
51+
p.worker(f)
52+
})
5253
}
5354
} else {
5455
select {
5556
case p.limiter <- struct{}{}:
5657
// If we are below our limit, spawn a new worker rather
5758
// than waiting for one to become available.
58-
p.handle.Go(p.worker)
59-
60-
// We know there is at least one worker running, so wait
61-
// for it to become available. This ensures we never spawn
62-
// more workers than the number of tasks.
63-
p.tasks <- f
59+
p.handle.Go(func() {
60+
p.worker(f)
61+
})
6462
case p.tasks <- f:
6563
// A worker is available and has accepted the task.
6664
return
@@ -149,11 +147,15 @@ func (p *Pool) WithContext(ctx context.Context) *ContextPool {
149147
}
150148
}
151149

152-
func (p *Pool) worker() {
150+
func (p *Pool) worker(initialFunc func()) {
153151
// The only time this matters is if the task panics.
154152
// This makes it possible to spin up new workers in that case.
155153
defer p.limiter.release()
156154

155+
if initialFunc != nil {
156+
initialFunc()
157+
}
158+
157159
for f := range p.tasks {
158160
f()
159161
}

0 commit comments

Comments
 (0)