DEV Community

Thiago Machado
Thiago Machado

Posted on

Entendendo Goroutines

Go se destaca por sua capacidade de construir aplicações concorrentes de forma simples e eficiente. Uma das características que a torna isso é as Goroutines, uma das funcionalidades mais poderosas da linguagem. Se você já trabalhou com outras linguagens, provavelmente está familiarizado com threads, mas as Goroutines são diferentes.

O que são Goroutines?

Image description

Resumidamente são funções ou métodos que rodam concorrentemente com outras funções ou métodos. Elas são mais leves que threads do SO, então você pode criar milhares de Goroutines com muito menos sobrecarga.

O que são Threads e porque Goroutines conseguem ser mais leves?

Threads são basicamente unidades de execução dentro de um processo. Um processo pode ter várias threads, todas compartilhando o mesmo espaço de memória mas com sua própria pilha de execução, que é basicamente uma estrutura de dados que armazena informações sobre as funções ativas em um programa. Threads do SO são gerenciadas e escaladas pelo SO, e também possuem um limite prático de milhares de threads por processo e tamanho de pilha fixo (geralmente 1MB ou mais por thread).

Já as Goroutines são "green threads" ou threads em nível de usuário, gerenciadas pelo runtime do Go, tamanho de pilha dinâmico começando apenas com 2KB podendo expandir ou diminuir de acordo com a necessidade. Por isso Goroutines conseguem ser mais leves.

O que é Concorrência e qual a diferença do Paralelismo?

Image description

Concorrência é o ato de lidar com várias tarefas ao mesmo tempo, já o Paralelismo executa tarefas simultaneamente em múltiplos processadores. Meio confuso, mas você vai entender melhor agora: A concorrência envolve mais estrutura e organização. Veja no exemplo abaixo:

Já o Paralelismo envolve mais execução, realmente rodando ao mesmo tempo, veja no exemplo abaixo:

O que são Channels?

Image description

Channels são "canais" de comunicação entre Goroutines. Eles permitem que Goroutines se comuniquem e sincronizem sua execução. Exemplo de comunicação entre Goroutines usando Channels:

func main() {
    ch := make(chan string)

    go func() {
        ch <- "Mensagem da goroutine"
    }()

    msg := <-ch
    fmt.Println(msg)
}
Enter fullscreen mode Exit fullscreen mode

Agora vamos finalizar com exemplos de uso de Goroutines:

// 1. Fazendo café e torrada ao mesmo tempo
func cafeDaManha() {
   fmt.Println("Iniciando café da manhã...") // 1º: Aparece primeiro

   go fazerCafe()    // 2º: "Começando a fazer café..."
   go fazerTorrada() // 3º: "Começando a fazer torrada..."

   // Espera 5 segundos para tudo ficar pronto
   time.Sleep(5 * time.Second)
   fmt.Println("Café da manhã pronto!") // Último: Aparece depois de 5 segundos
}

func fazerCafe() {
   fmt.Println("Começando a fazer café...")
   time.Sleep(3 * time.Second) 
   fmt.Println("Café pronto!") // 4º: Aparece após 3 segundos
}

func fazerTorrada() {
   fmt.Println("Começando a fazer torrada...")
   time.Sleep(2 * time.Second)
   fmt.Println("Torrada pronta!") // 5º: Aparece após 2 segundos
}

/* Saída:
Iniciando café da manhã...
Começando a fazer café...
Começando a fazer torrada...
Torrada pronta! (após 2 segundos)
Café pronto! (após 3 segundos)
Café da manhã pronto! (após 5 segundos)
*/

// 2. Contagem com Goroutines
func contagem() {
   go contar("A", 5) // Começa a contar imediatamente
   go contar("B", 5) // Começa a contar imediatamente

   time.Sleep(6 * time.Second)
}

func contar(nome string, até int) {
   for i := 1; i <= até; i++ {
       fmt.Printf("%s: %d\n", nome, i)
       time.Sleep(1 * time.Second)
   }
}

/* Saída (aproximada - as linhas A e B se misturam):
A: 1
B: 1
A: 2
B: 2
A: 3
B: 3
A: 4
B: 4
A: 5
B: 5
*/

// 3. Enviando mensagens simples
func mensagens() {
   canal := make(chan string)

   go func() {
       canal <- "Olá!"      // 1ª mensagem enviada
       canal <- "Tudo bem?" // 2ª mensagem enviada
       canal <- "Tchau!"    // 3ª mensagem enviada
   }()

   fmt.Println(<-canal) // 1º: Imprime "Olá!"
   fmt.Println(<-canal) // 2º: Imprime "Tudo bem?"
   fmt.Println(<-canal) // 3º: Imprime "Tchau!"
}

/* Saída:
Olá!
Tudo bem?
Tchau!
*/
Enter fullscreen mode Exit fullscreen mode

Top comments (0)