The Semaphore Pattern is a concurrency control mechanism that limits the number of goroutines accessing a shared resource simultaneously. It uses a semaphore to maintain a counter representing the availability of finite resources.
- Semaphore: A counter that manages access to limited resources.
- Concurrency Control: Prevents system overload by regulating resource usage.
- Create a Semaphore: Initialize a semaphore with a fixed limit representing the number of available resources.
- Wait for Semaphore: Each goroutine must "wait" for access if no resources are available.
- Release Semaphore: Once done, the goroutine releases the resource for others to use.
Limit the number of goroutines accessing a resource at the same time.
package main
import (
"fmt"
"sync"
"time"
)
func main() {
// Semaphore with a maximum of 3 resources
sem := make(chan struct{}, 3)
var wg sync.WaitGroup
// 5 goroutines that need to access the resource
for i := 1; i <= 5; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
// Wait until there is space in the semaphore
sem <- struct{}{} // Occupy a resource in the semaphore
fmt.Printf("Goroutine %d is using the resource\n", i)
time.Sleep(2 * time.Second) // Simulate work
// Release the resource
<-sem
fmt.Printf("Goroutine %d has released the resource\n", i)
}(i)
}
// Wait for all goroutines to finish
wg.Wait()
}
sem := make(chan struct{}, 3)
: Initializes a semaphore with a maximum of 3 resources.sem <- struct{}{}
: Each goroutine "waits" by sending a value to the semaphore. If the semaphore is full, the goroutine blocks until space becomes available.<-sem
: Once the task is complete, the goroutine releases the resource, making it available for others.
The Semaphore Pattern provides an efficient way to manage concurrent access to limited resources, ensuring system stability and avoiding resource contention.