DEV Community

Matheus Mina
Matheus Mina

Posted on

Introdução a concorrência em Go

Uma das funcionalidades mais legais de Go é a facilidade de se utilizar concorrência. A linguagem nos fornece as chamadas goroutines que são lighweight threads gerenciadas pelo própio runtime do Go. Concorrência nos permite rodar diversas funções ao mesmo tempo. Isso é extremamente útil caso você queira melhorar a performance de sua aplicação.

Para utilizar essa funcionalidade, basta colocar a palavra-chave go antes de qualquer função e ela automaticamente vai estar rodando de forma concorrente. Para ficar mais fácil de entender, vamos ver um pouco de código. Aqui está implementado o SleepSort, é um algoritmo de ordenação que utiliza um sleep para poder colocar cada elemento no seu lugar.

package main

import (
    "fmt"
    "time"
)

func main() {
    arr := []int{3, 1, 5, 6, 9, 2, 0}

    fmt.Println("Sorting", arr)
    for _, v := range arr {
        go Sort(v)
    }
}

func Sort(x int) {
    time.Sleep(time.Duration(x) * time.Second)
    fmt.Printf("%d ", x)
}
Enter fullscreen mode Exit fullscreen mode

Nesse código, temos a função sort que dorme por x segundos e imprime o valor desejado. Assim, ao final da execução de todo mundo, vamos ter impresso o array na ordem certa, correto? Infelizmente a resposta é: não!

Resposta inicial do código

Como a função roda de forma concorrente ao processo principal, só vemos na saída o que este processo retorna. Uma maneira de solucionar este problema é fazermos os processos concorrentes se comunicarem de alguma forma com o processo principal. Para isso, a linguagem nos fornece o conceito de channel. Podemos entender este conceito como um canal, ou conduinte, responsável por enviar dados entre os processos. Vamos atualizar nosso código então para utilizar channels.

package main

import (
    "fmt"
    "time"
)

func main() {
    arr := []int{3, 1, 5, 6, 9, 2, 0}
    c := make(chan int)

    fmt.Println("Sorting", arr)
    for _, v := range arr {
        go sort(v, c)
    }

    fmt.Println("Sorted:")
    for range arr {
        x := <-c
        fmt.Printf("%d ", x)
    }
}

func sort(x int, c chan int) {
    time.Sleep(time.Duration(x) * time.Second)
    c <- x
}
Enter fullscreen mode Exit fullscreen mode

E finalmente temos como resposta:

Resposta após utilizarmos channels

Como podemos notar, existe um operador especial para os channels que é o <-. Para entender como ele funciona, é só pensar que o dado vai seguir o sentido da seta. Por exemplo, dentro da função sort o dado é enviado através do canal usando c <- x e na função principal recebemos um valor do canal e atribuímos em uma nova variável utilizando x := <-c.

Também é importante dizer que a assinatura da função sort foi alterada para receber um chan. Esse chan então é inicializado na função principal e passado para as goroutines.

Como podemos ver, começar a utilizar concorrência em Go é simples. A linguagem também suporta opções mais avançadas, mas isso fica para um próximo blog post. Se curtiu o assunto, você também pode me encontrar no Twitter, Github ou LinkedIn. Você também pode achar esse texto em Inglês.

Top comments (0)