package main import ( "fmt" "sync" "time" ) // worker simulates a task that takes some time func worker(id int, semaphore chan struct{}, wg *sync.WaitGroup) { defer wg.Done() // Acquire a slot from the semaphore semaphore <- struct{}{} fmt.Printf("Worker %d: Acquired semaphore, starting task... ", id) // Simulate work time.Sleep(time.Duration(2 + (id % 3)) * time.Second) // 2, 3, or 4 seconds fmt.Printf("Worker %d: Task finished. ", id) // Release the slot back to the semaphore <-semaphore } func main() { const maxConcurrency = 3 const totalTasks = 10 // Create a buffered channel to act as a semaphore // Its capacity limits the number of concurrent goroutines semaphore := make(chan struct{}, maxConcurrency) var wg sync.WaitGroup fmt.Printf("Main: Starting %d tasks with a maximum concurrency of %d. ", totalTasks, maxConcurrency) for i := 1; i <= totalTasks; i++ { wg.Add(1) go worker(i, semaphore, &wg) } wg.Wait() // Wait for all workers to complete fmt.Println("Main: All tasks completed.") }