├── Mutex ├── README.md ├── main.go └── raceConditions │ ├── README.md │ └── main.go ├── README.md ├── channels ├── README.md ├── bidirectional │ └── main.go ├── bufferedChannels │ └── main.go ├── main.go └── select │ └── select.go ├── exercicios ├── BankBalance │ ├── main.go │ └── readme.md ├── barberShop │ ├── README.md │ └── main.go ├── diningPhilosophers │ ├── README.md │ └── main.go └── pizzaria │ ├── README.md │ └── main.go ├── go.mod ├── go.sum ├── goroutine ├── README.md └── main.go └── waitGroups ├── README.md ├── main.go └── main_test.go /Mutex/README.md: -------------------------------------------------------------------------------- 1 | ## Mutex 2 | 3 | ![Captura de Tela 2023-01-10 às 15 52 08](https://user-images.githubusercontent.com/75685022/211637033-db7c8951-e273-4556-bb13-dfde4a795e35.png) 4 | 5 | 6 | 7 | Mutex permite que você lide com situação de race condition (concorrência) 8 | Você pode dar lock em um dado enquanto estiver usando, e após terminar é só dar unlock. 9 | 10 | Dessa maneira as goroutines irão acessar o dado com segurança. 11 | Caso o dado esteja em lock, e outra goroutine tente acessar, ela irá esperar até que o dado esteja disponivel. 12 | 13 | ## Exemplo 14 | 15 | ```go 16 | func updateMessage(s string, m *sync.Mutex) { 17 | defer wg.Done() 18 | m.Lock() 19 | msg = s 20 | m.Unlock() 21 | } 22 | 23 | func main() { 24 | 25 | var mutex sync.Mutex 26 | 27 | wg.Add(2) 28 | updateMessage("Message 2", &mutex) 29 | updateMessage("Message 1", &mutex) 30 | wg.Wait() 31 | 32 | fmt.Println(msg) 33 | } 34 | ``` 35 | 36 | 37 | -------------------------------------------------------------------------------- /Mutex/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | var msg string 9 | var wg sync.WaitGroup 10 | 11 | func updateMessage(s string, m *sync.Mutex) { 12 | 13 | defer wg.Done() 14 | 15 | m.Lock() 16 | msg = s 17 | m.Unlock() 18 | } 19 | 20 | func main() { 21 | 22 | var mutex sync.Mutex 23 | 24 | wg.Add(2) 25 | updateMessage("Message 2", &mutex) 26 | 27 | updateMessage("Message 1", &mutex) 28 | 29 | wg.Wait() 30 | 31 | fmt.Println(msg) 32 | 33 | } 34 | -------------------------------------------------------------------------------- /Mutex/raceConditions/README.md: -------------------------------------------------------------------------------- 1 | go run -race . 2 | -------------------------------------------------------------------------------- /Mutex/raceConditions/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | var msg string 9 | var wg sync.WaitGroup 10 | 11 | func updateMessage(s string) { 12 | defer wg.Done() 13 | msg = s 14 | } 15 | 16 | func main() { 17 | 18 | wg.Add(2) 19 | go updateMessage("Teste 1") 20 | go updateMessage("Teste 2") 21 | wg.Wait() 22 | 23 | fmt.Println(msg) 24 | } 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Repositório. 2 | Esse repo contem explicações e exemplos utilizando `goroutines`, `waitGroups`, `channels` e `mutex`. Cada um dos temas tem seu próprio readme com uma breve explicação. 3 | Você também ira encontrar uma lista com alguns exercícios conhecidos para praticar concorrência. Juntamente com a explicação e a resolução do problema. 4 | 5 | 6 | Contribua!! 7 | 8 | 9 | ![GitHub top language](https://img.shields.io/github/languages/top/mariarobertap/go-concurrency?color=green) 10 | ![GitHub forks](https://img.shields.io/github/forks/mariarobertap/go-concurrency?style=social) 11 | ![GitHub Repo stars](https://img.shields.io/github/stars/mariarobertap/go-concurrency?style=social) 12 | 13 | 14 | 15 | # Tópicos 16 | 17 | - [Goroutines](https://github.com/mariarobertap/go-concurrency/tree/main/goroutine) 18 | - [Waigroups](https://github.com/mariarobertap/go-concurrency/tree/main/waitGroups) 19 | - [Channels](https://github.com/mariarobertap/go-concurrency/tree/main/channels) 20 | - [Mutex](https://github.com/mariarobertap/go-concurrency/tree/main/Mutex) 21 | 22 | 23 | # Exercícios 24 | 25 | - [Barbearia](https://github.com/mariarobertap/go-concurrency/tree/main/exercicios/barberShop) 26 | - [Pizzaria](https://github.com/mariarobertap/go-concurrency/tree/main/exercicios/pizzaria) 27 | - [Banco](https://github.com/mariarobertap/go-concurrency/tree/main/exercicios/BankBalance) 28 | - [Dining Philosophers](https://github.com/mariarobertap/go-concurrency/tree/main/exercicios/diningPhilosophers) 29 | 30 | -------------------------------------------------------------------------------- /channels/README.md: -------------------------------------------------------------------------------- 1 |

O que são Channels?

2 | 3 | ![Gravação de Tela 2023-03-08 às 10 15 26](https://user-images.githubusercontent.com/75685022/224519931-89e5e1c8-ede3-400e-8d08-0038bf317029.gif) 4 | 5 | 6 | 7 | Um channel é um sistema de comunicação que permite uma go-routine enviar valores a outra go-routine.
8 | O channel nada mais é do que um cano utilizado para transmitir informações entre go-routines. 9 | 10 |

Como criar um channel?

11 | 12 | ```go 13 | ch := make(chan int) 14 | ``` 15 | 16 |

Tipos de canais

17 | 18 | Os canais podem ser especificos ou gerais ou seja eles podem ser unidirecionais ou bidirecionais. 19 | 20 |

Exemplo de canal bidirecional:

21 | 22 | ```go 23 | ch := make(chan string) 24 | ``` 25 | Este canal pode ser convertido para um canal especifico(send ou receive) 26 | 27 |

Exemplo de canais unidirecionais:

28 | 29 | ```go 30 | // canal de envio 31 | cs := ch<- 32 | //canal de recebimento 33 | cr := <-ch 34 | ``` 35 | Canais unidirecionais não podem ser convertidos para bidirecional nem de um send para um receive depois de sua declaração 36 | 37 | exemplos: 38 | ```go 39 | //only bidirectional channels can become send or receive channels 40 | package main 41 | //it works :) 42 | func main(){ 43 | channel := make(chan string) 44 | channelSend := func() { 45 | channel <- "Hello" 46 | } 47 | go channelSend() 48 | channelReceive := <-channel 49 | fmt.Println(channelReceive) 50 | } 51 | 52 | ``` 53 | ```go 54 | package main 55 | //It doesn't work :( 56 | func main(){ 57 | cs := make(chan<-string) 58 | cr := make(<-chan string) 59 | 60 | (<-chan string)(cs) 61 | (chan<- string)(cr) 62 | (chan string)(cs) 63 | (chan string)(cr) 64 | } 65 | ``` 66 | 67 |

Exemplo usando funções:

68 | 69 | ```go 70 | package main 71 | 72 | import "fmt" 73 | 74 | func sendNumber(cs chan<- int64, number int64){ 75 | cs <- number 76 | } 77 | func receiveAndReturnANumber(cr <-chan int64)int64{ 78 | number := <-cr 79 | return number 80 | } 81 | func main(){ 82 | ch := make(chan int64) 83 | go sendNumber(ch,1075897489377463545) 84 | number := receiveAndReturnANumber(ch) 85 | fmt.Println(number) 86 | } 87 | ``` 88 | 89 | "Don't communicate by sharing memory; share memory by communicating. (R. Pike)" 90 | -------------------------------------------------------------------------------- /channels/bidirectional/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | 7 | messagesChannel := make(chan string)//bidirectional channel 8 | 9 | go sendMessage(messagesChannel,"Oi do sendMessage")//send channel 10 | receiveMessage(messagesChannel)//receive channel 11 | } 12 | 13 | func sendMessage(cs chan<- string,message string){ 14 | cs<-message 15 | } 16 | 17 | func receiveMessage(cr <-chan string){ 18 | fmt.Printf(<-cr) 19 | } 20 | -------------------------------------------------------------------------------- /channels/bufferedChannels/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | 10 | //This channel have a buffer of 10. I can put 10 values in this channel. 11 | //Everytime the listenToChan function get the value from the chan, i get one free space.. 12 | ch := make(chan int, 10) 13 | 14 | go listenToChannel(ch) 15 | 16 | for i := 0; i < 100; i++ { 17 | 18 | fmt.Println("sendind data to channel", i) 19 | 20 | ch <- i 21 | fmt.Println("Sent data to channel", i) 22 | 23 | } 24 | 25 | close(ch) 26 | 27 | } 28 | 29 | func listenToChannel(ch chan int) { 30 | 31 | for { 32 | i := <-ch 33 | 34 | fmt.Println("Got", i, " from channel") 35 | 36 | time.Sleep(1 * time.Second) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /channels/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | func main() { 9 | ping := make(chan string) 10 | pong := make(chan string) 11 | var userInput string 12 | 13 | go shout(ping, pong) 14 | 15 | for { 16 | 17 | fmt.Print("->") 18 | 19 | fmt.Scanln(&userInput) 20 | 21 | if userInput == "q" { 22 | break 23 | } 24 | 25 | ping <- userInput 26 | 27 | response := <-pong 28 | 29 | fmt.Println(response) 30 | 31 | } 32 | close(ping) 33 | close(pong) 34 | } 35 | 36 | //Receiver and sender. receiver <-chan. sender chan<- 37 | func shout(receiver <-chan string, sender chan<- string) { 38 | 39 | for { 40 | s, ok := <-receiver 41 | if !ok { 42 | fmt.Println("Channel is closed.") 43 | } 44 | sender <- fmt.Sprintf("%s!!", strings.ToUpper(s)) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /channels/select/select.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | fmt.Println("----- SELECT WITH CHANNELS -----") 10 | ch1 := make(chan string) 11 | ch2 := make(chan string) 12 | 13 | go server1(ch1) 14 | go server2(ch2) 15 | 16 | for { 17 | //Note that case 1 and 2, and 3 and 4 are exactly the same. if this happens, go will choose randomly. 18 | select { 19 | case s1 := <-ch1: 20 | fmt.Println("CASE 1 - ", s1) 21 | case s2 := <-ch1: 22 | fmt.Println("CASE 2 - ", s2) 23 | case s3 := <-ch2: 24 | fmt.Println("CASE 3 - ", s3) 25 | case s4 := <-ch2: 26 | fmt.Println("CASE 4 - ", s4) 27 | //default - default case can also be used to avoid deadlocks 28 | } 29 | } 30 | 31 | } 32 | 33 | func server1(ch chan string) { 34 | for { 35 | time.Sleep(1 * time.Second) 36 | ch <- "SERVER1. This is a message sent from server 1." 37 | } 38 | } 39 | func server2(ch chan string) { 40 | for { 41 | time.Sleep(1 * time.Second) 42 | ch <- "SERVER 2. This is a message sent from server 2." 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /exercicios/BankBalance/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | var wg sync.WaitGroup 9 | 10 | type Income struct { 11 | Source string 12 | Amount int 13 | } 14 | 15 | func main() { 16 | 17 | var bankBalance int 18 | var balance sync.Mutex 19 | 20 | income := []Income{ 21 | { 22 | Source: "Main job", 23 | Amount: 1000, 24 | }, 25 | { 26 | Source: "Investments", 27 | Amount: 500, 28 | }, 29 | } 30 | 31 | wg.Add(len(income)) 32 | for i := 0; i < len(income); i++ { 33 | 34 | go func(i int, income Income) { 35 | defer wg.Done() 36 | for week := 0; week < 4; week++ { 37 | balance.Lock() 38 | temp := bankBalance 39 | temp += income.Amount 40 | bankBalance = temp 41 | balance.Unlock() 42 | 43 | } 44 | 45 | }(i, income[i]) 46 | 47 | } 48 | wg.Wait() 49 | 50 | fmt.Printf("Total amount earned $ %d", bankBalance) 51 | 52 | } 53 | -------------------------------------------------------------------------------- /exercicios/BankBalance/readme.md: -------------------------------------------------------------------------------- 1 | BankBalance 2 | -------------------------------------------------------------------------------- /exercicios/barberShop/README.md: -------------------------------------------------------------------------------- 1 | A barbershop consist of a waiting room with n chairs, and a barber room with one barber chair. Given the following constraints: 2 | 3 | If there are no customers to be served, the barber goes to sleep 4 | If a customer enters the barbershop and all chairs are occupied, then the customer leaves the shop. 5 | If the barber is busy, but chairs are available, then the customer sits in one of the free chairs. 6 | If the barber is sleeping, the customer wakes up the barber. 7 | -------------------------------------------------------------------------------- /exercicios/barberShop/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "time" 7 | 8 | "github.com/fatih/color" 9 | ) 10 | 11 | var seatingCapacity = 10 12 | var arrivalRate = 100 13 | var cutDuration = 1000 * time.Millisecond 14 | var timeOpen = 10 * time.Second 15 | 16 | type BarberShop struct { 17 | ShopCapacity int 18 | HairCutDuration time.Duration 19 | NumberOfBarbers int 20 | BarbersDoneChan chan bool 21 | ClientsChan chan string 22 | Open bool 23 | } 24 | 25 | func main() { 26 | 27 | rand.Seed(time.Now().UnixNano()) 28 | 29 | color.Yellow("The Sleeping Barber Problem") 30 | color.Yellow("---------------------------") 31 | 32 | //Esse é um buffered channel, com o tamanho == ao tamanho da capacidade de clientes da barbearia. 33 | clientChan := make(chan string, seatingCapacity) 34 | doneChan := make(chan bool) 35 | 36 | shop := BarberShop{ 37 | ShopCapacity: seatingCapacity, 38 | HairCutDuration: cutDuration, 39 | NumberOfBarbers: 0, 40 | ClientsChan: clientChan, 41 | BarbersDoneChan: doneChan, 42 | Open: true, 43 | } 44 | 45 | color.Green("The shop is open for the day") 46 | 47 | shop.AddBarber("Frank") 48 | shopClosing := make(chan bool) 49 | closed := make(chan bool) 50 | 51 | //Verificando se 10s já se passaram para fechar a loja 52 | go func() { 53 | //Waiting until is time to close the store. 54 | <-time.After(timeOpen) 55 | shopClosing <- true 56 | shop.closeShopForDay() 57 | closed <- true 58 | 59 | }() 60 | 61 | i := 0 62 | //Enviando clientes para a barbearia. 63 | go func() { 64 | for { 65 | //get a random number with average arrival date 66 | random := rand.Int() % (2 * arrivalRate) 67 | select { 68 | case <-shopClosing: 69 | return 70 | case <-time.After(time.Millisecond * time.Duration(random)): 71 | shop.addClient(fmt.Sprintf("Maria #%d", i)) 72 | i++ 73 | 74 | } 75 | } 76 | }() 77 | 78 | //Esperando até que tudo estiver finalizado. 79 | <-closed 80 | 81 | } 82 | 83 | func (shop *BarberShop) AddBarber(barberName string) { 84 | shop.NumberOfBarbers++ 85 | go func() { 86 | isSleeping := false 87 | 88 | color.Yellow(" %s Goes to the waiting room to check for clients.", barberName) 89 | 90 | for { 91 | if len(shop.ClientsChan) == 0 { 92 | color.Yellow("%s Takes a nap. No clients in the waiting room", barberName) 93 | isSleeping = true 94 | } 95 | 96 | //Verifica se o canal está fechado. 97 | //Se estiver, significa que a loja está fechada. 98 | //Mas como é um buffered channel, ainda pode ter dados no buffer. 99 | //Atendendo o critério do exercicio, que se a loja estiver fechada 100 | //ainda pode ter clientes na sala de espera. 101 | client, open := <-shop.ClientsChan 102 | 103 | if open { 104 | if isSleeping { 105 | color.Yellow("Client %s wakes up %s", client, barberName) 106 | isSleeping = false 107 | } 108 | 109 | shop.cutHair(barberName, client) 110 | 111 | } else { 112 | shop.sendBarberHome(barberName) 113 | return 114 | } 115 | } 116 | }() 117 | } 118 | 119 | func (shop *BarberShop) cutHair(barberName, client string) { 120 | color.Green("%s is cutting %s hair", barberName, client) 121 | time.Sleep(shop.HairCutDuration) 122 | } 123 | 124 | func (shop *BarberShop) sendBarberHome(barberName string) { 125 | color.Cyan("%s is going home", barberName) 126 | shop.BarbersDoneChan <- true 127 | 128 | } 129 | func (shop *BarberShop) closeShopForDay() { 130 | 131 | color.Cyan("Closing shop for the day") 132 | //Fechando o canal para não aceitar novos clientes na sala de espera. 133 | //Os que ainda estáo esperando, continuam até serem atendidos. 134 | close(shop.ClientsChan) 135 | shop.Open = false 136 | 137 | for i := 0; i < shop.NumberOfBarbers; i++ { 138 | //esperando receber um valor aqui == 139 | <-shop.BarbersDoneChan 140 | 141 | } 142 | 143 | close(shop.BarbersDoneChan) 144 | 145 | color.Green("-------------------") 146 | color.Green("Barber shop is closed") 147 | 148 | } 149 | 150 | func (shop *BarberShop) addClient(client string) { 151 | color.Green("*** %s arrives! ", client) 152 | 153 | if shop.Open { 154 | select { 155 | case shop.ClientsChan <- client: 156 | color.Blue("%s Takes a seat in the waiting room", client) 157 | default: 158 | //Buffered channel is full 159 | color.Red("Waiting room is full %s leaves", client) 160 | } 161 | 162 | } else { 163 | color.Red("The shop is already closed, so %s leaves", client) 164 | } 165 | 166 | } 167 | -------------------------------------------------------------------------------- /exercicios/diningPhilosophers/README.md: -------------------------------------------------------------------------------- 1 | The dining philosophers problem states that there are 5 philosophers sharing a circular table and they eat and think alternatively. There is a bowl of rice for each of the philosophers and 5 chopsticks. A philosopher needs both their right and left chopstick to eat. A hungry philosopher may only eat if there are both chopsticks available.Otherwise a philosopher puts down their chopstick and begin thinking again. 2 | 3 | The dining philosopher is a classic synchronization problem as it demonstrates a large class of concurrency control problems. 4 | -------------------------------------------------------------------------------- /exercicios/diningPhilosophers/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | type Philosopher struct { 10 | name string 11 | rightFork int 12 | leftFork int 13 | } 14 | 15 | var philosofers = []Philosopher{ 16 | {name: "Plato", leftFork: 4, rightFork: 0}, 17 | {name: "Socrates", leftFork: 0, rightFork: 1}, 18 | {name: "Aristotle", leftFork: 1, rightFork: 2}, 19 | {name: "Pascal", leftFork: 2, rightFork: 3}, 20 | {name: "Locke", leftFork: 3, rightFork: 4}, 21 | } 22 | 23 | // 24 | var hunger = 1 // how many times does a person eat? 25 | var eatTime = 1 * time.Second 26 | var thinkTime = 3 * time.Second 27 | var sleepTime = 1 * time.Second 28 | var listPhilosofers []string 29 | 30 | func main() { 31 | fmt.Println("Dining philosophers problem") 32 | fmt.Println("---------------------------") 33 | fmt.Println("The table is empty.") 34 | 35 | dine() 36 | 37 | fmt.Println("The table is empty.") 38 | 39 | } 40 | 41 | func dine() { 42 | 43 | wg := &sync.WaitGroup{} 44 | wg.Add(len(philosofers)) 45 | 46 | seated := &sync.WaitGroup{} 47 | seated.Add(len(philosofers)) 48 | list := &sync.Mutex{} 49 | 50 | var forks = make(map[int]*sync.Mutex) 51 | 52 | for i := 0; i < len(philosofers); i++ { 53 | forks[i] = &sync.Mutex{} 54 | } 55 | 56 | //Start the meal. 57 | for i := 0; i < len(philosofers); i++ { 58 | //Fire of a goroutine for the current philosopher 59 | go diningProblem(philosofers[i], wg, forks, seated, list) 60 | 61 | } 62 | 63 | wg.Wait() 64 | fmt.Println(listPhilosofers) 65 | 66 | } 67 | 68 | func diningProblem(philosopher Philosopher, wg *sync.WaitGroup, forks map[int]*sync.Mutex, seated *sync.WaitGroup, list *sync.Mutex) { 69 | defer wg.Done() 70 | 71 | //seat the philoshphers at the table 72 | 73 | fmt.Printf("%s is seated at the table.\n", philosopher.name) 74 | 75 | seated.Done() 76 | //Wait until everyone is seated. 77 | seated.Wait() 78 | 79 | for i := 0; i < hunger; i++ { 80 | //get a lock on both forks 81 | if philosopher.leftFork > philosopher.rightFork { 82 | forks[philosopher.rightFork].Lock() 83 | fmt.Printf(" %s Takes the rifht fork.\n", philosopher.name) 84 | forks[philosopher.leftFork].Lock() 85 | fmt.Printf(" %s Takes the left fork.\n", philosopher.name) 86 | 87 | } else { 88 | forks[philosopher.leftFork].Lock() 89 | fmt.Printf(" %s Takes the left fork.\n", philosopher.name) 90 | forks[philosopher.rightFork].Lock() 91 | fmt.Printf(" %s Takes the rifht fork.\n", philosopher.name) 92 | } 93 | 94 | fmt.Printf(" %s has both forks, is eating..\n", philosopher.name) 95 | time.Sleep(eatTime) 96 | forks[philosopher.leftFork].Unlock() 97 | forks[philosopher.rightFork].Unlock() 98 | 99 | fmt.Printf(" %s Is done eating.\n", philosopher.name) 100 | 101 | } 102 | list.Lock() 103 | listPhilosofers = append(listPhilosofers, philosopher.name) 104 | list.Unlock() 105 | 106 | } 107 | -------------------------------------------------------------------------------- /exercicios/pizzaria/README.md: -------------------------------------------------------------------------------- 1 | Pizzaria 2 | -------------------------------------------------------------------------------- /exercicios/pizzaria/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "time" 7 | 8 | "github.com/fatih/color" 9 | ) 10 | 11 | const NumberOfPizzas = 10 12 | 13 | var pizzasMade, pizzasFailed, total int 14 | 15 | type Producer struct { 16 | data chan PizzaOrder 17 | quit chan chan error 18 | } 19 | 20 | type PizzaOrder struct { 21 | pizzaNumber int 22 | message string 23 | success bool 24 | } 25 | 26 | func makePizza(pizzaId int) *PizzaOrder { 27 | pizzaId++ 28 | 29 | if pizzaId <= NumberOfPizzas { 30 | delay := rand.Intn(5) + 1 31 | fmt.Printf("Received order # %d\n", pizzaId) 32 | 33 | rnd := rand.Intn(12) + 1 34 | msg := "" 35 | success := false 36 | 37 | if rnd < 5 { 38 | pizzasFailed++ 39 | 40 | } else { 41 | pizzasMade++ 42 | 43 | } 44 | total++ 45 | 46 | fmt.Printf("Makind pizza #%d. It will take %d seconds....\n", pizzaId, delay) 47 | time.Sleep(time.Duration(delay) * time.Second) 48 | 49 | if rnd <= 2 { 50 | msg = fmt.Sprintf("We ran out of ingredients for pizza #%d\n", pizzaId) 51 | } else if rnd <= 4 { 52 | msg = fmt.Sprintf("***The cook quit while making the pizza #%d\n", pizzaId) 53 | } else { 54 | success = true 55 | msg = fmt.Sprintf("Pizza order #%d is ready!\n", pizzaId) 56 | 57 | } 58 | 59 | return &PizzaOrder{ 60 | pizzaNumber: pizzaId, 61 | message: msg, 62 | success: success, 63 | } 64 | } 65 | 66 | return &PizzaOrder{ 67 | pizzaNumber: pizzaId, 68 | } 69 | } 70 | 71 | func pizzaria(pizzaJob *Producer) { 72 | var i = 0 73 | 74 | for { 75 | currentPizza := makePizza(i) 76 | if currentPizza != nil { 77 | i = currentPizza.pizzaNumber 78 | select { 79 | case pizzaJob.data <- *currentPizza: 80 | 81 | case quitChan := <-pizzaJob.quit: 82 | close(pizzaJob.data) 83 | close(quitChan) 84 | return 85 | } 86 | } 87 | 88 | } 89 | 90 | } 91 | 92 | func (p *Producer) Close() error { 93 | ch := make(chan error) 94 | 95 | p.quit <- ch 96 | 97 | return <-ch 98 | } 99 | 100 | func main() { 101 | rand.Seed(time.Now().UnixNano()) 102 | color.Cyan("The Pizzaria is open for bussiness") 103 | color.Cyan("----------------------------------") 104 | 105 | pizzaJob := &Producer{ 106 | data: make(chan PizzaOrder), 107 | quit: make(chan chan error), 108 | } 109 | 110 | go pizzaria(pizzaJob) 111 | 112 | //CONSUMER - consumes the pizzaria data 113 | for i := range pizzaJob.data { 114 | if i.pizzaNumber <= NumberOfPizzas { 115 | if i.success { 116 | color.Green(i.message) 117 | color.Green("Order %d is out for delivery!", i.pizzaNumber) 118 | } else { 119 | color.Red(i.message) 120 | color.Red("The customer is really mad!") 121 | } 122 | } else { 123 | color.Cyan("Done making pizzas!") 124 | color.Cyan("----------------------------------") 125 | err := pizzaJob.Close() 126 | if err != nil { 127 | color.Red("Error closing channel!") 128 | 129 | } 130 | } 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module waitGroups 2 | 3 | go 1.18 4 | 5 | require github.com/fatih/color v1.13.0 6 | 7 | require ( 8 | github.com/mattn/go-colorable v0.1.9 // indirect 9 | github.com/mattn/go-isatty v0.0.14 // indirect 10 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect 11 | ) 12 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= 2 | github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= 3 | github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U= 4 | github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 5 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 6 | github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= 7 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= 8 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 9 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 10 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= 11 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 12 | -------------------------------------------------------------------------------- /goroutine/README.md: -------------------------------------------------------------------------------- 1 |

Goroutine

2 | 3 | Se você já utilizou threads em outra linguagem, pode supor que as goroutines são similares as threads, 4 | uma das diferença é que as goroutines são muito mais leves. 5 | Uma goroutine nada mais é do que uma atividade que é execudada de forma concorrente. 6 | Você pode ter diversas atividades em um mesmo programa rodando de forma concorrente. 7 | 8 | Exemplo 9 | ```go 10 | package main 11 | 12 | import ( 13 | "fmt" 14 | "sync" 15 | ) 16 | 17 | func printSomething(s string, wg *sync.WaitGroup) { 18 | defer wg.Done() 19 | fmt.Println(s) 20 | } 21 | 22 | func main() { 23 | var wg sync.WaitGroup 24 | 25 | wg.Add(1) 26 | go printSomething("Hello from goroutine 1", &wg) 27 | fmt.Println("Hello from main-goroutine.") 28 | wg.Wait() 29 | 30 | } 31 | ``` 32 | -------------------------------------------------------------------------------- /goroutine/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | func printSomething(s string, wg *sync.WaitGroup) { 9 | defer wg.Done() 10 | fmt.Println(s) 11 | } 12 | 13 | func main() { 14 | var wg sync.WaitGroup 15 | 16 | wg.Add(1) 17 | go printSomething("Hello from goroutine 1", &wg) 18 | fmt.Println("Hello from main-goroutine.") 19 | 20 | wg.Wait() 21 | 22 | } 23 | -------------------------------------------------------------------------------- /waitGroups/README.md: -------------------------------------------------------------------------------- 1 | # WaitGroups 2 | 3 | Levando em conta que GoRoutines são funções que são executadas em paralelo como uma thread, seu programa pode finalizar antes que sua GoRoutine finalize. 4 | Para contornar isso, existe os waitGroups, utilizados para informar ao seu programa que ele deve aguardar por uma ou mais GoRoutines finalizar 5 | 6 | 7 | - WaitGroup espera por uma quantidade de goroutines finalizar. Impedindo que seu programa finalize antes que as go routines terminem de rodar. 8 | - As go routines são responsáveis por avisar que ela está finalizada. 9 | 10 | # Exemplo: 11 | ```go 12 | var wg sync.WaitGroup 13 | 14 | func hello() { 15 | //Goroutine Avisando ao WaitGroup que finalizou. 16 | defer wg.Done() 17 | fmt.Println("hello from a goroutine!") 18 | } 19 | 20 | func main() { 21 | //wait group deve esperar por 1 goroutine finalizar 22 | wg.Add(1) 23 | //Go routine 24 | go hello() 25 | //Esperando Goroutine finalizar. 26 | wg.Wait() 27 | } 28 | ``` 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /waitGroups/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | func printSomething(s string, wg *sync.WaitGroup) { 9 | defer wg.Done() 10 | fmt.Println(s) 11 | } 12 | 13 | func main() { 14 | var wg sync.WaitGroup 15 | words := []string{ 16 | "test1", 17 | "test2", 18 | "test3", 19 | "test4", 20 | "test5", 21 | "test6", 22 | } 23 | 24 | wg.Add(len(words)) 25 | 26 | for i := 0; i < len(words); i++ { 27 | go printSomething(words[i], &wg) 28 | } 29 | 30 | wg.Wait() 31 | 32 | } 33 | -------------------------------------------------------------------------------- /waitGroups/main_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io" 5 | "os" 6 | "strings" 7 | "sync" 8 | "testing" 9 | ) 10 | 11 | func Test_printSomething(t *testing.T) { 12 | var wg sync.WaitGroup 13 | stdOut := os.Stdout 14 | r, w, _ := os.Pipe() 15 | os.Stdout = w 16 | expectedString := "testando" 17 | wg.Add(1) 18 | 19 | go printSomething(expectedString, &wg) 20 | 21 | wg.Wait() 22 | 23 | _ = w.Close() 24 | 25 | result, _ := io.ReadAll(r) 26 | output := string(result) 27 | 28 | os.Stdout = stdOut 29 | 30 | if !strings.Contains(output, expectedString) { 31 | t.Errorf("Expected = %s; Got = %s", expectedString, output) 32 | } 33 | } 34 | --------------------------------------------------------------------------------