Go Channel Patterns - Fan Out  Semaphore
Tags: go, programming, tutorial, beginners
Published: 2021-12-13 18:02:17

---
series: [Go Channel Patterns]
---

To improve my Go Programming skills and become a better Go engineer, I have recently purchased an excellent on-demand education from [Ardan Labs](https://www.ardanlabs.com/education/). Materials are created by an expert Go engineer, [Bill Kennedy](https://twitter.com/goinggodotnet).

{% twitter 1468657044907515910 %}


I have decide to record my process of learning how to write more idiomatic code, following Go best practices and design philosophies. 

This series of posts will describe channel patterns used for orchestration/signaling in Go via goroutines.

## Fan Out Semaphore Pattern

The main idea behind **Fan Out Semaphore Pattern** is to have:
- everything we had in the **Fan Out Pattern**:
  - a buffered channel that provides a signaling semantics 
  - a goroutine that starts multiple (child) goroutines to do some work
  - a multiple (child) goroutines that do some work and use signaling channel to signal the work is done

- **PLUS** the addition of a:
  - new **semaphore channel** used to restrict the number of child goroutines that can be schedule to run

![Fan Out Pattern](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/75veyea6p6vynzpc3zse.png)

### Example

In **Fan Out Pattern** we have multiple `employees` that have some work to do. 

We also have a `manager` (`main` goroutine) that waits on that work to be done. Once each `employee` work is done, `employee` notifies `manager` by sending a signal (`paper`) via communication channel `ch`. 

In **Fan Out Semaphore Pattern** we have an additional constraint in terms of maximum number of `employees` that can do work at any given moment. 

#### Explanation

For example, we have 100 employees, but only 10 available free seats in the office space. It doesn't matter that 100 employees are available to do the work when we only have adequate space for 10 employees at any given moment. Other 90 employees have to wait until on of those 10 finish the work and frees the seat.

Good use case for this pattern would be batch processing, where we have some amount of work to do, but we want to limit the number of active executors at any given moment.

Feel free to try the example on [Go Playground](https://play.golang.com/p/znS2WqIrWeG)

```go
package main

import (
	"fmt"
	"math/rand"
	"time"
)

func main() {
	emps := 10

	// buffered channel, one slot for every goroutine
	// send side can complete without receive (non-blocking)
	ch := make(chan string, emps)

	// max number of RUNNING goroutines at any given time
	// g := runtime.NumCPU()
	g := 2
	// buffered channel, based on the max number of the goroutines in RUNNING state
	// added to CONTROL the number of goroutines in RUNNING state
	sem := make(chan bool, g)

	for e := 0; e < emps; e++ {
		// create 10 goroutines in the RUNNABLE state
		// one for each employee
		go func(emp int) {

			// when goroutine moves from RUNNABLE to RUNNING state
			// send signal/value inside a `sem` channel
			// if `sem` channel buffer is full, this will block
			// e.g. employee takes a seat
			sem <- true
			{
				// simulate the idea of unknown latency (do not use in production)
				// e.g. employee does some work
				time.Sleep(time.Duration(rand.Intn(200)) * time.Millisecond)

				// once work is done, signal on ch channel
				ch <- "paper"
				fmt.Println("employee : sent signal : ", emp)
			}

			// once all work is done pull the value from the `sem` channel
			// give place to another goroutine to do the work
			// e.g. employee stands up and free up seat for another employee
			<-sem
		}(e)
	}

	// wait for all employee work to be done
	for emps > 0 {
		// receive signal sent from the employee
		p := <-ch

		emps--
		fmt.Println(p)
		fmt.Println("manager : received signal : ", emps)

	}
}
```

### Result
```sh
go run main.go

employee : sent signal :  9
paper
manager : received signal :  9
employee : sent signal :  4
paper
manager : received signal :  8
employee : sent signal :  1
paper
manager : received signal :  7
employee : sent signal :  2
paper
manager : received signal :  6
employee : sent signal :  3
paper
manager : received signal :  5
employee : sent signal :  8
paper
manager : received signal :  4
employee : sent signal :  6
paper
manager : received signal :  3
employee : sent signal :  5
paper
manager : received signal :  2
employee : sent signal :  0
paper
manager : received signal :  1
employee : sent signal :  7
paper
manager : received signal :  0
```


## Conclusion
In this article, fan out semaphore channel pattern was described. In addition, simple implementation was provided.

Readers are encouraged to check out excellent [Ardan Labs](https://www.ardanlabs.com/education/) education materials to learn more.

Resources:
1. [Ardan Labs](https://www.ardanlabs.com/)
2. [Cover image by Igor Mashkov from Pexels](https://www.pexels.com/photo/radio-telescope-against-sky-with-stars-6325001/)
3. [Fan out picture](https://habr.com/ru/company/ua-hosting/blog/490750/)