Bounded Parallelism: ограниченное число воркеров

К задачам
Сложная
Concurrency

Условие задачи

У тебя есть 100 задач, каждая занимает около 100 миллисекунд. Нужно обработать их с максимальной эффективностью, но не запускать более 10 задач одновременно. Реализуй worker pool с ограничением по количеству параллельных задач.

package main

import (
    "fmt"
    "time"
)

func doWork(id int) {
    time.Sleep(100 * time.Millisecond)
    fmt.Println("done", id)
}

func main() {
    // TODO: реализуй обработку 100 задач с ограничением на 10 параллельных
}
package main

import (
    "fmt"
    "time"
)

func doWork(id int) {
    time.Sleep(100 * time.Millisecond)
    fmt.Println("done", id)
}

func main() {
    // TODO: реализуй обработку 100 задач с ограничением на 10 параллельных
}

Подсказка

- Используй семафор на основе буферизованного канала. - Можно также использовать фиксированный pool горутин и канал задач. - Не забудь дождаться завершения всех задач.

Решение

Bounded Parallelism позволяет контролировать нагрузку, не создавая слишком много горутин. Это часто применяется при работе с БД, сетью, API.

package main

import (
    "fmt"
    "sync"
    "time"
)

func doWork(id int) {
    time.Sleep(100 * time.Millisecond)
    fmt.Println("done", id)
}

func main() {
    var wg sync.WaitGroup
    sem := make(chan struct{}, 10)

    for i := 0; i < 100; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()
            sem <- struct{}{}
            doWork(id)
            <-sem
        }(i)
    }

    wg.Wait()
}
package main

import (
    "fmt"
    "sync"
    "time"
)

func doWork(id int) {
    time.Sleep(100 * time.Millisecond)
    fmt.Println("done", id)
}

func main() {
    var wg sync.WaitGroup
    sem := make(chan struct{}, 10)

    for i := 0; i < 100; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()
            sem <- struct{}{}
            doWork(id)
            <-sem
        }(i)
    }

    wg.Wait()
}