This content originally appeared on DEV Community and was authored by b0r
To improve my Go Programming skills and become a better Go engineer, I have recently purchased an excellent on-demand education from Ardan Labs. Materials are created by an expert Go engineer, Bill Kennedy.
Ardan Labs@ardanlabs🎙️Welcome @MGallagher2010 to the podcast! 🎙️
Engineers often have a negative impression of recruiters but sometimes you find a special person like Martin. As a specialist in #golang, Martin is dedicated to finding the best opportunity for you & your family 😊19:01 PM - 08 Dec 2021
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
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
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
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 education materials to learn more.
Resources:
This content originally appeared on DEV Community and was authored by b0r
b0r | Sciencx (2021-12-13T18:02:17+00:00) Go Channel Patterns – Fan Out Semaphore. Retrieved from https://www.scien.cx/2021/12/13/go-channel-patterns-fan-out-semaphore/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.