Bounded Parallelism in Go: The... Note

Bounded Parallelism in Go: The Semaphore Pattern That Caps Goroutines

The Go programming language's concurrency model, while powerful with goroutines, can lead to issues like overwhelming downstream services or hitting system limits when many goroutines are launched simultaneously. This is particularly true for I/O-bound tasks like fetching numerous URLs. Launching a goroutine per URL, a common initial approach, can exhaust resources such as file descriptors or trigger API rate limits. The core problem is unbounded fan-out, where the number of concurrent operations is not controlled.To address this, concurrency must be capped. One effective method is using a buffered channel as a counting semaphore, where sending to the channel acquires a slot and receiving releases it. Another approach for more complex scenarios is the x/sync/semaphore package, which allows for weighted concurrency limiting and context-aware acquisition. For tasks that involve error handling and require stopping other operations upon failure, the x/sync/errgroup package with its SetLimit method is the recommended solution.The errgroup also provides a derived context that gets cancelled when an error occurs, allowing other goroutines to gracefully exit. Writing to distinct slice indices from multiple goroutines is safe, but shared mutable state requires synchronization. Choosing the right concurrency bounding tool depends on whether the work is uniform, if error propagation is needed, and if weighted limits are necessary. The optimal concurrency limit is determined by the weakest resource in the chain, often an external API's tolerance, rather than CPU count. Bounded parallelism ensures that goroutine count scales with resources, not input size, preventing service meltdowns.
CdXz5zHNQW_KTysiL4mCy.webp