Aula 25 – Tutorial Golang – Goroutines
Aula 25 – Tutorial Golang – Goroutines
Página principal do blog
Todas as aulas desse curso
Aula 24 Aula 26
Redes Sociais:
Meus links de afiliados:
Hostinger
Digital Ocean
One.com
Melhore seu NETWORKING
https://digitalinnovation.one/
Participe de comunidades de desenvolvedores:
Fiquem a vontade para me adicionar ao linkedin.
E também para me seguir no https://github.com/toticavalcanti.
Código final da aula:
https://github.com/toticavalcanti
Canais do Youtube
Toti
Backing Track / Play-Along
Código Fluente
Putz!
Vocal Techniques and Exercises
PIX para doações
Aula 25 – Tutorial Golang – Goroutines
Goroutines
O que são Goroutines?
Goroutines são funções ou métodos que são executados simultaneamente com outras funções ou métodos.
Goroutines podem ser consideradas threads leves.
Em Go, todo programa tem pelo menos uma goroutine: a goroutine main.
O custo de criar uma Goroutine é pequeno quando comparado a uma thread.
Portanto, é comum que os aplicativos Go tenham milhares de Goroutines sendo executadas simultaneamente.
Vantagens de Goroutines sobre as threads
Goroutines são extremamente baratas quando comparadas as threads.
Elas têm apenas alguns kb de tamanho na pilha, e a pilha pode crescer e diminuir de acordo com as necessidades da aplicação, enquanto no caso de threads o tamanho da pilha deve ser especificado e é fixo.
As Goroutines são multiplexadas para um número menor de threads no SO.
Pode haver apenas uma thread em um programa com milhares de Goroutines.
Se qualquer Goroutine nesse bloco de thread disser que está aguardando entrada do usuário, outra thread no sistema operacional, será criada, e as Goroutines restantes serão movidas para a nova thread do SO.
Tudo isso é cuidado em tempo de execução e nós, como programadores, somos abstraídos desses detalhes intrincecos e recebemos uma API limpa para trabalhar com simultaneidade.
Goroutines se comunicam usando canais.
Os canais, por design, evitam que as condições de corrida aconteçam ao acessar a memória compartilhada usando Goroutines.
Os canais podem ser pensados como um tubo através do qual as Goroutines se comunicam.
Como iniciar uma Goroutine?
Prefixe a chamada de função ou método com a palavra-chave go e você terá uma nova Goroutine rodando simultaneamente.
Vamos criar uma Goroutine? 🙂
package main
import (
"fmt"
)
func hello() {
fmt.Println("Hello world goroutine")
}
func main() {
go hello()
fmt.Println("main function")
}
O go hello() logo no início da main(), inicia uma nova Goroutine.
Agora a função hello() será executada simultaneamente com a função main().
A função main() é executada em sua própria Goroutine e é chamada de Goroutine principal.
Execute este programa e você terá uma surpresa!
Este programa produz apenas o texto informando: função principal.
Saída:
main function
O que aconteceu com a Goroutine que começamos?
Precisamos entender as duas principais propriedades das Goroutines para entender por que isso acontece.
Quando uma nova Goroutine é iniciada, a chamada da Goroutine retorna imediatamente.
Ao contrário das funções, o controle não espera que a Goroutine termine de executar.
O controle retorna imediatamente para a próxima linha de código após a chamada de Goroutine e quaisquer valores de retorno do Goroutine são ignorados.
A Goroutine principal deve estar em execução para que qualquer outra Goroutine seja executada.
Se a Goroutine principal for encerrada, o programa será encerrado e nenhuma outra Goroutine será executada.
Acho que agora você será capaz de entender por que nossa Goroutine não funcionou.
Após a chamada para go hello(), o controle retornou imediatamente para a próxima linha de código sem esperar que o hello goroutine termine e imprimiu a função main().
Em seguida, a Goroutine principal foi encerrada, pois não há outro código para executar e, portanto, a Goroutine hello() não teve a chance de ser executada.
Vamos corrigir isso agora!
package main
import (
"fmt"
"time"
)
func hello() {
fmt.Println("Hello world goroutine")
}
func main() {
go hello()
time.Sleep(1 * time.Second)
fmt.Println("main function")
}
Na parte do código onde tem: time.Sleep(1 * time.Second), chamamos o método Sleep do pacote time, que faz a rotina go na qual ele está sendo executada, dormir(sleep).
Neste caso, a goroutine principal é adormecida por 1 segundo.
Agora a chamada para go hello(), tem tempo suficiente para ser executada antes que a Goroutine principal termine.
Este programa primeiro imprime a goroutine Hello world, espera 1 segundo e depois imprime a função main.
Essa maneira de usar o Sleep na Goroutine principal para esperar que outras Sleep terminem sua execução, é um hack que estamos usando para entender como as Goroutines funcionam.
Vamos ver mais um exemplo:
package main
import (
"fmt"
)
func main() {
hello("Martin")
hello("Lucia")
hello("Michal")
hello("Jozef")
hello("Peter")
}
func hello(name string) {
fmt.Printf("Hello %s!\n", name)
}
Nesse código acima, temos a chamada normal, síncrona, da função hello(), agora vamos ver o mesmo código com Gourotine.
package main
import (
"fmt"
)
func hello(name string) {
fmt.Printf("Hello %s!\n", name)
}
func main() {
go hello("Martin")
go hello("Lucia")
go hello("Michal")
go hello("Jozef")
go hello("Peter")
}
Veja que não houve tempo de imprimir, porque a Goroutine principal finalizou muito rápido, sem esperar a execução das chamadas da função hello().
Para fazer a Goroutine principal esperar, ao invés de usar o recurso do Sleep como fizemos antes, vamos adicionar fmt.Scanln() para o programa ficar esperando alguma entrada do usuário para encerrar a execução.
package main
import (
"fmt"
)
func hello(name string) {
fmt.Printf("Hello %s!\n", name)
}
func main() {
go hello("Martin")
go hello("Lucia")
go hello("Michal")
go hello("Jozef")
go hello("Peter")
fmt.Scanln()
}
Canais
Os canais podem ser usados para bloquear a Goroutine principal até que todas as outras Goroutines terminem sua execução.