Семафор: ограничение параллелизма

К задачам
Средняя
Concurrency

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

Реализуй запуск 20 задач, каждая из которых делает "работу" в течение 1 секунды. Разреши одновременное выполнение только 5 задач. Для ограничения используй семафор на базе буферизованного канала.

package main

import (
    "fmt"
    "time"
)

func worker(id int, sem chan struct{}) {
    // TODO: реализуй ограничение через семафор
}

func main() {
    sem := make(chan struct{}, 5)

    for i := 1; i <= 20; i++ {
        go worker(i, sem)
    }

    // TODO: дождись завершения всех задач
}
package main

import (
    "fmt"
    "time"
)

func worker(id int, sem chan struct{}) {
    // TODO: реализуй ограничение через семафор
}

func main() {
    sem := make(chan struct{}, 5)

    for i := 1; i <= 20; i++ {
        go worker(i, sem)
    }

    // TODO: дождись завершения всех задач
}

Подсказка

- Перед началом работы: sem <- struct{}{} - После завершения: <-sem - Для ожидания всех горутин используй sync.WaitGroup.

Решение

Буферизованный канал отлично подходит для реализации семафора, т.к. блокирует при превышении лимита.

package main

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

func worker(id int, sem chan struct{}, wg *sync.WaitGroup) {
    defer wg.Done()

    sem <- struct{}{} // заняли слот
    fmt.Printf("Worker %d started
", id)
    time.Sleep(time.Second)
    fmt.Printf("Worker %d finished
", id)
    <-sem // освободили слот
}

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

    for i := 1; i <= 20; i++ {
        wg.Add(1)
        go worker(i, sem, &wg)
    }

    wg.Wait()
}
package main

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

func worker(id int, sem chan struct{}, wg *sync.WaitGroup) {
    defer wg.Done()

    sem <- struct{}{} // заняли слот
    fmt.Printf("Worker %d started
", id)
    time.Sleep(time.Second)
    fmt.Printf("Worker %d finished
", id)
    <-sem // освободили слот
}

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

    for i := 1; i <= 20; i++ {
        wg.Add(1)
        go worker(i, sem, &wg)
    }

    wg.Wait()
}