Quando utilizar Goroutines?

Uma dúvida que assombra a maioria dos desenvolvedores Go, e não exclusivamente iniciantes, é sobre quando utilizar goroutines.

Nesse post vou dar algumas dicas para ajudar na análise e tomada de decisão na hora de adotar ou não a utilização de goroutines em seu projeto.

Antes de mais nada, assim como qualquer coisa relacionada a tecnologia, nem todo projeto faz sentido utilizar goroutines. Você pode até pensar, “meu sistema está lento. Já sei, vou usar goroutines para resolver.”, gastar muito tempo, já que SÓ colocar um go antes da chamada da função pode não ser o suficiente, e no final não ver melhora nenhuma ou até mesmo notar uma piora no desempenho.

Leia mais »

Implementando um worker pool

Agora que já falamos praticamente tudo que havia para ser falado sobre goroutines e channels, vamos utilizar esse conhecimento para implementar um worker pool.

Se você não conhece o termo, um worker pool é basicamente uma coleção de threads que ficam esperando tarefas serem atribuídas a elas. Quando a thread finaliza a tarefa que foi atribuída, se torna disponível novamente para execução de uma nova tarefa.

Antes de começar a meter a mão na massa, vou deixar aqui o link para os outros posts da série sobre goroutines e channels.

O worker pool que vamos implementar irá somar os dígitos passados e armazenar o resultado.

Leia mais »

Múltiplos channels e a cláusula select

Dando continuidade ao nosso estudo de goroutines e channels, nesse post vamos falar sobre uma cláusula pouco utilizada.

Antes de começar, vou deixar os links para os outros posts caso você tenha perdido algum da série.

A cláusula select é utilizada para que uma função consiga trabalhar com múltiplos channels. Ela bloqueia a execução da função até que um dos channels esteja pronto para ser executado. Caso mais de um channel esteja pronto para ser executado, ela selecionará de forma aleatória qual executar.

Para tentar ficar um pouco mais claro, vamos escrever um pequeno programa para ilustrar o comportamento.

Leia mais »

Buffer de mensagens em channels

Dando continuidade ao nosso estudo sobre channels, nesse post vamos falar sobre como fazer buffer de mensagens.

Até agora, todos os exemplos que vimos de channels no post “O que são e como utilizar channels” não fazem buffer das mensagens, ou seja, ao escrever uma mensagem no channel, a goroutine que escreveu fica aguardando até que outra goroutine faça a leitura daquela informação. Somente após a leitura é que a goroutine de escrita consegue voltar a escrever algo no channel.

Utilizar buffer de mensagens faz com que a goroutine de escrita seja bloqueado de escrever no channel somente quando o buffer estiver cheio. Já a de leitura só ficará bloqueada quando o buffer estiver vazio. Logo, utilizar um buffer de mensagens pode ajudar com que o trabalho das goroutines seja mais fluido.

Para criar um channel com buffer, tudo que precisamos fazer é passar um parâmetro adicional na sua criação para definir a capacidade máxima.

Leia mais »

O que são e como utilizar channels

Algumas semanas atrás fizemos um post falando sobre o que são e como funcionam as goroutines (link do post). Nesse post, mencionamos sobre os channels quando fizemos um “fix” para que o programa esperasse a execução da goroutine antes de terminar.

No post de hoje vamos aprofundar um pouco sobre o que são os channels e como podemos usá-los.

Podemos pensar em channels como sendo uma espécie de tunel de comunidação entre goroutines, onde uma goroutine consegue enviar informações para outra antes mesmo de terminar sua execução. Nesse mesmo cenário, a goroutine que recebe a informação, ficaria pausada até as informações chegarem.

Quando vamos declarar um channel ou inicializa-lo, precisamos associar um tipo de dado a ele. Esse tipo de dado é o tipo que ele estará apto à transportar entre goroutines.

Leia mais »

Benchmark: API com gorilla mux usando goroutines vs sem goroutines

Já faz um certo tempo que eu queria dedicar algumas horas para testar um cenário onde os dados que uma request deveria apresentar fossem obtidos com goroutines vs sem goroutines.

Finalmente esse dia chegou, mas antes de apresentar os resultados, vamos construir juntos uma simples API onde vamos executar os testes para medir a performance.

O objetivo da request será obter o nome e a quantidade total de pedidos que uma pessoa já realizou.

Para não ter que envolver banco de dados, vamos criar duas variáveis contendo os dados que podemos retornar.

var (
    people = [][]string{
        []string{"1", "Tiago Temporin"},
        []string{"2", "João Silva"},
        []string{"3", "Mateus Cardoso"},
        []string{"4", "Maria Lina"},
        []string{"5", "Camila Manga"},
        []string{"6", "Joice Santos"},
        []string{"7", "Lucas Leal"},
        []string{"8", "Vanessa da Terra"},
        []string{"9", "Mateus de Morais"},
        []string{"10", "Maria Luiza"},
    }

    orders = [][]string{
        []string{"1", "5"},
        []string{"2", "10"},
        []string{"3", "0"},
        []string{"4", "0"},
        []string{"5", "2"},
        []string{"6", "9"},
        []string{"7", "3"},
        []string{"8", "15"},
        []string{"9", "3"},
        []string{"10", "7"},
    }
)
Leia mais »

O que são e como funcionam as Goroutines

Na semana passada explicamos a diferença entre concorrência e paralelismo (link do post), o que serviu de base para o post de hoje, onde vamos explicar as famosas goroutines.

Goroutines são funções ou métodos executados em concorrência. Podemos pensar nelas como uma especie de lightweight thread que são gerenciadas pelo runtime do Go.

Chamamos de lightweight thread pois o custo para sua criação é muito menor quando comparada com um thread de verdade. Outro ponto positivo é que o runtime consegue aumentar ou diminuir a quantidade de goroutines de acordo com a necessidade da aplicação, enquanto o número de thread normalmente é fixo.

Leia mais »