Skip to content

Instantly share code, notes, and snippets.

@crazyoptimist
Last active February 4, 2024 03:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save crazyoptimist/f996290b167b14d1ac6b214c564b44f1 to your computer and use it in GitHub Desktop.
Save crazyoptimist/f996290b167b14d1ac6b214c564b44f1 to your computer and use it in GitHub Desktop.
Semaphore Concurrency Pattern with Buffered Channel in Go
package main
import (
"fmt"
"time"
)
const (
NUM_WORKERS = 100
NUM_JOBS = 1000
)
type Token struct{}
func main() {
// A semaphore is a buffered channel
semaphore := make(chan Token, NUM_WORKERS)
for i := 1; i <= NUM_JOBS; i++ {
job := i
// Simply start goroutines when you have concurrent work.
semaphore <- Token{}
go func() {
fmt.Printf("Performing %d th job\n", job)
// fmt.Printf("Current Goroutines: %d\n", runtime.NumGoroutine())
time.Sleep(100 * time.Millisecond)
<-semaphore
}()
}
// This ensures the main goroutine does not ends before all the jobs are performed
for i := 0; i < NUM_WORKERS; i++ {
semaphore <- Token{}
}
}
@crazyoptimist
Copy link
Author

crazyoptimist commented Feb 3, 2024

The Worker Pool pattern might be regarded as an anti-pattern because of inefficiency, which means it allows idle goroutines especially at the end of a job batch. Above concurrency pattern using semaphore channel eliminates the issue.

Simply, start goroutines when you have concurrent work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment