Go
Пул воркеров на горутинах
Обработка задач в несколько потоков с WaitGroup, каналами и отменой через context.
Код
package main
import (
"context"
"fmt"
"sync"
"time"
)
type Job struct {
ID int
URL string
}
type Result struct {
JobID int
Value string
Err error
}
func worker(ctx context.Context, id int, jobs <-chan Job, results chan<- Result, wg *sync.WaitGroup) {
defer wg.Done()
for {
select {
case <-ctx.Done():
return
case job, ok := <-jobs:
if !ok {
return
}
time.Sleep(100 * time.Millisecond) // полезная работа
results <- Result{JobID: job.ID, Value: fmt.Sprintf("worker %d: %s", id, job.URL)}
}
}
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
jobs := make(chan Job, 100)
results := make(chan Result, 100)
var wg sync.WaitGroup
for i := 1; i <= 5; i++ {
wg.Add(1)
go worker(ctx, i, jobs, results, &wg)
}
go func() {
for i := 1; i <= 20; i++ {
jobs <- Job{ID: i, URL: fmt.Sprintf("https://example.com/%d", i)}
}
close(jobs)
}()
go func() {
wg.Wait()
close(results)
}()
for res := range results {
if res.Err != nil {
fmt.Printf("задача %d: ошибка %v\n", res.JobID, res.Err)
continue
}
fmt.Println(res.Value)
}
}