Concurrency examples

 Concurrency examples

1. Go program that uses the sync package's WaitGroup type to wait for a group of goroutines to finish.

The main function creates a WaitGroup value and calls its Add method with a value of 5 to specify that it is waiting for 5 goroutines to finish. Then it starts 5 goroutines by calling the Square function in a loop, passing the loop index and a pointer to the WaitGroup value as arguments.

The Square function takes an integer no and a pointer to a WaitGroup value as arguments. It calculates the square of no and prints it along with the value of no. After that, it calls the Done method on the WaitGroup value to indicate that it has finished. The defer statement ensures that the Done method is called even if the function panics or returns early.

Finally, the main function calls the Wait method on the WaitGroup value to block until all the goroutines have finished. This ensures that the program doesn't exit before all the goroutines have completed their work.

2. Go program that uses channels to communicate between goroutines.

The worker function is a goroutine that takes an integer ID, a read-only channel of integers called jobs, and a write-only channel of integers called results as arguments. It processes each job by reading it from the jobs channel, sleeping for one second, and then writing the result (which is twice the value of the job) to the results channel.

The main function creates two channels, jobs and results, using the make function. It then starts three worker goroutines by calling the worker function in a loop, passing the loop index, the jobs channel, and the results channel as arguments.

The main function then sends five jobs to the workers by writing to the jobs channel in a loop. It then closes the jobs channel to indicate that no more jobs will be sent.

Finally, the main function reads the results from the results channel in a loop, discarding the values. This is done to ensure that the program doesn't exit before all the results have been processed by the main goroutine.

3. Go program that uses the sync package's WaitGroup type and the select statement to read from multiple channels concurrently.

The main function creates two channels, intCh and strCh, using the make function. It also creates a WaitGroup value and calls its Add method with a value of 2 to specify that it is waiting for two goroutines to finish. Then it starts two goroutines by calling the intRoutine and strRoutine functions, passing them the channels and a pointer to the WaitGroup value as arguments.

The intRoutine and strRoutine functions are goroutines that write integers and strings to the respective channels in a loop. They both close the channels when they are done writing to them.

The main function then enters a loop and uses the select statement to concurrently read from the two channels. It reads from the intCh channel first and then the strCh channel. For each channel, it uses the second form of the channel receive operation, which returns a second value that indicates whether the channel is closed. If the channel is closed, it sets the channel variable to nil so that it is not selected in the select statement anymore.

The main function breaks out of the loop when both channels are nil, which indicates that both goroutines have finished. Finally, it calls the Wait method on the WaitGroup value to block until both goroutines have finished.
4.Go program that uses channels and the sync package's WaitGroup type to communicate between goroutines and synchronize their execution.

The main function creates two channels, dataCh and quit, using the make function. It also creates a WaitGroup value and calls its Add method with a value of 2 to specify that it is waiting for two goroutines to finish. Then it starts two goroutines by calling the sendRoutine and printRoutine functions, passing them the channels and a pointer to the WaitGroup value as arguments.

The sendRoutine function is a goroutine that writes integers to the dataCh channel in a loop and sends a boolean value true on the quit channel when it writes the value 654. It then closes both channels.

The printRoutine function is a goroutine that reads from both the dataCh and quit channels using the select statement. If it receives a value on the dataCh channel, it prints it. If it receives a value true on the quit channel, it prints "Quit" and returns. If it receives the zero value of the channel type (false for a boolean channel), it breaks out of the loop.

The main function calls the Wait method on the WaitGroup value to block until both goroutines have finished. This ensures that the program doesn't exit before both goroutines have completed their work.


5. Producer consumber problem 

The main function seeds the random number generator, creates a Producer value called pizzaJob, and starts a goroutine that runs the pizzeria function in the background, passing it a pointer to the pizzaJob value as an argument.

The pizzeria function is a goroutine that generates PizzaOrder values by calling the makePizza function in a loop. It sends each PizzaOrder value on the data channel of the pizzaJob value using the select statement. If it receives a value on the quit channel of the pizzaJob value, it closes both the data and quit channels and returns.

The main function then enters a loop and reads from the data channel of the pizzaJob value. If the pizzaNumber field of the PizzaOrder value is less than or equal to NumberOfPizzas, it prints the message field using the color package's Green or Red function depending on the value of the success field. If the pizzaNumber field is greater than NumberOfPizzas, it prints a message using the color package's Cyan function and then closes the data channel by calling the Close method on the pizzaJob value.

Finally, the main function prints the number of pizzas made, failed, and total using the color package's Yellow function.

package main

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

"github.com/fatih/color"
)

const NumberOfPizzas = 10

var pizzaMade, pizzaFailed, total int

type Producer struct {
data chan PizzaOrder
quit chan chan error
}

type PizzaOrder struct {
pizzaNumber int
message string
success bool
}

func (p *Producer) Close() error {
ch := make(chan error)
p.quit <- ch
return <-ch
}

func makePizza(pizzaNumber int) *PizzaOrder {
pizzaNumber++
if pizzaNumber <= NumberOfPizzas {
delay := rand.Intn(5) + 1
fmt.Printf("Received order #%d!\n", pizzaNumber)

rnd := rand.Intn(12) + 1
msg := ""
success := false

if rnd < 5 {
pizzaFailed++
} else {
pizzaMade++
}
total++

fmt.Printf("Making pizza #%d. It will take %d seconds....\n",
pizzaNumber, delay)
// delay bit
time.Sleep(time.Duration(delay) * time.Second)

if rnd <= 2 {
msg = fmt.Sprintf("We ran out of ingredients for pizza #%d!",
pizzaNumber)
} else if rnd <= 4 {
msg = fmt.Sprintf("The cook quit while making pizza #%d!",
pizzaNumber)
} else {
success = true
msg = fmt.Sprintf("Pizza order#%d is ready!", pizzaNumber)
}

p := PizzaOrder{
pizzaNumber: pizzaNumber,
message: msg,
success: success,
}
return &p
}
return &PizzaOrder{
pizzaNumber: pizzaNumber,
}
}

func pizzeria(pizzaMaker *Producer) {
// keep track of which pizza we are making
var i = 0

// run forever or until receive a quit notification

// try to make pizzas
for {
currentPizza := makePizza(i)
if currentPizza != nil {
i = currentPizza.pizzaNumber
select {
// try to make pizza, send data to channel
case pizzaMaker.data <- *currentPizza:

case quitChan := <-pizzaMaker.quit:
// close channels
close(pizzaMaker.data)
close(quitChan)
return
}
}
}
}

func main() {
// seed the random number generator
rand.Seed(time.Now().UnixNano())

// print out a message
color.Cyan("The Pizzeris is open for business !")
color.Cyan("-----------------------------------")

// create a producer
pizzaJob := &Producer{
data: make(chan PizzaOrder),
quit: make(chan chan error),
}

// run the producer in the background
go pizzeria(pizzaJob)

// create and run consumer

for i := range pizzaJob.data {
if i.pizzaNumber <= NumberOfPizzas {
if i.success {
color.Green(i.message)
color.Green("Order #%d is out for delivery!",
i.pizzaNumber)
} else {
color.Red(i.message)
color.Red("The customer is really mad!")
}
} else {
color.Cyan("Done making pizzas...")
err := pizzaJob.Close()
if err != nil {
color.Red("Error closing channel", err)
}
}
}

// print out the ending message
color.Cyan("----------------")
color.Cyan("Done for the day")

color.Cyan("We make %d pizzas, but failed to make %d, with %d attempts in total.",
pizzaMade, pizzaFailed, total)

switch {
case pizzaFailed > 9:
color.Red("It was an awful day...")
case pizzaFailed >= 6:
color.Red("It was not very good day...")
case pizzaFailed >= 4:
color.Yellow("It was a okay day...")
case pizzaFailed >= 2:
color.Yellow("It was a pretty good day...")
default:
color.Green("It was a great day")
}

}


Comments

Popular posts from this blog

Golang Interview Questions Part 1 Theory Top 50 Question

Complete Golang Development setup on Linux (Ubuntu 20.04 )

Best GitHub repositories for Go