Documentation
¶
Overview ¶
Package taskgroup manages a collection of cooperating goroutines. It simplifies common concerns of waiting for goroutine termination and collecting errors.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type ErrorFunc ¶
An ErrorFunc is called by a group each time a task reports an error. Its return value replaces the reported error, so the ErrorFunc can filter or suppress errors by modifying or discarding the input error.
func Listen ¶
Listen adapts f to an ErrorFunc. The resulting function returns task errors unmodified.
Example ¶
package main
import (
"errors"
"fmt"
"github.com/creachadair/taskgroup"
)
func main() {
g := taskgroup.New(taskgroup.Listen(func(e error) {
fmt.Println(e)
}))
g.Go(func() error { return errors.New("heard you") })
fmt.Println(g.Wait()) // the error was preserved
}
Output: heard you heard you
func Trigger ¶
func Trigger(f func()) ErrorFunc
Trigger adapts f to an ErrorFunc. The resulting function returns task errors unmodified.
Example ¶
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/creachadair/taskgroup"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
const badTask = 5
g := taskgroup.New(taskgroup.Trigger(cancel))
for i := 0; i < 10; i++ {
i := i
g.Go(func() error {
if i == badTask {
return fmt.Errorf("task %d failed", i)
}
select {
case <-ctx.Done():
return nil
case <-time.After(10 * time.Second):
return nil
}
})
}
if err := g.Wait(); err == nil {
log.Fatal("I expected an error here")
} else {
fmt.Println(err.Error())
}
}
Output: task 5 failed
type Group ¶
type Group struct {
// contains filtered or unexported fields
}
A Group manages a collection of cooperating goroutines. New tasks can be added to the group via the Go method. The caller can wait for the tasks to complete by calling the Wait method.
The group collects any errors returned by the tasks in the group. The first non-nil error reported by any task (and not otherwise filtered) is returned from the Wait method.
Example ¶
package main
import (
"fmt"
"github.com/creachadair/taskgroup"
)
func main() {
msg := make(chan string)
g := taskgroup.New(nil)
g.Go(func() error {
msg <- "ping"
fmt.Println(<-msg)
return nil
})
g.Go(func() error {
fmt.Println(<-msg)
msg <- "pong"
return nil
})
g.Wait()
fmt.Println("<done>")
}
Output: ping pong <done>
func New ¶
New constructs a new, empty group. Add tasks to the group using g.Go. Wait for the group to complete with g.Wait. If ef != nil, it is called each time a task reports an error. The error returned by the ErrorFunc replaces the task's error.
func (*Group) Limit ¶
Limit returns g and a function that starts each task passed to it in g, allowing no more than n tasks to be active concurrently. If n ≤ 0, the start function is equivalent to g.Go, which enforces no limit.
Example ¶
package main
import (
"fmt"
"sync"
"time"
"github.com/creachadair/taskgroup"
)
func main() {
var p peakValue
g, start := taskgroup.New(nil).Limit(4)
for i := 0; i < 100; i++ {
start(func() error {
p.inc()
defer p.dec()
time.Sleep(1 * time.Microsecond)
return nil
})
}
g.Wait()
fmt.Printf("Max active ≤ 4: %v\n", p.max <= 4)
}
type peakValue struct {
μ sync.Mutex
cur, max int
}
func (p *peakValue) inc() {
p.μ.Lock()
p.cur++
if p.cur > p.max {
p.max = p.cur
}
p.μ.Unlock()
}
func (p *peakValue) dec() {
p.μ.Lock()
p.cur--
p.μ.Unlock()
}
Output: Max active ≤ 4: true
func (*Group) Wait ¶
Wait blocks until all the goroutines currently active in the group have returned, and all reported errors have been delivered to the callback. Wait returns the first non-nil error returned by any of the goroutines in the group and not filtered by an ErrorFunc.
After a call to Wait returns, the group is ready for reuse.