Aşağıdaki örneklerde, birçok işi tamamlamak için bir döngüde arabelleğe alınmış bir kanalla sınırlı miktarda goroutin çalıştırıyoruz. Her örneğin kendi gereksinimleri vardır ve listelendiği gibi farklı paketler kullanır.



errgroup


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
}

waitgroup


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)
}