27/08/2020 - GO
In examples below we run limited amount of goroutines with a buffered channel in a loop in order to complete many jobs. Each examples have their own requirements and use different packages as listed.
package main
import (
"context"
"fmt"
"log"
"time"
"golang.org/x/sync/errgroup"
)
var (
done = make(chan struct{})
workers = make(chan struct{}, 10)
)
func main() {
go func() {
eg, ctx := errgroup.WithContext(context.Background())
for i := 1; i <= 100; i++ {
i := i
workers <- struct{}{}
eg.Go(func() error {
select {
case <-ctx.Done():
return ctx.Err()
default:
if err := do(ctx, i); err != nil {
return err
}
<-workers
return nil
}
})
}
if err := eg.Wait(); err != nil {
log.Fatalln("force exit", err)
}
done <- struct{}{}
}()
for {
select {
case <-time.After(time.Second):
log.Println("graceful exit at timeout")
return
case <-done:
log.Println("all done")
return
}
}
}
func do(ctx context.Context, i int) error {
time.Sleep(time.Millisecond * 100)
fmt.Println("JOB:", i)
return nil
}
package main
import (
"fmt"
"log"
"sync"
"time"
)
var (
done = make(chan struct{})
workers = make(chan struct{}, 10)
waiter = &sync.WaitGroup{}
)
func main() {
go func() {
for i := 1; i <= 100; i++ {
waiter.Add(1)
workers <- struct{}{}
go func(i int) {
defer waiter.Done()
do(i)
<-workers
}(i)
}
waiter.Wait()
done <- struct{}{}
}()
for {
select {
case <-time.After(time.Second):
log.Println("graceful exit at timeout")
return
case <-done:
log.Println("all done")
return
}
}
}
func do(i int) {
time.Sleep(time.Millisecond * 100)
fmt.Println("JOB:", i)
}