Семафор: ограничение параллелизма
Условие задачи
Реализуй запуск 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()
}