Escrevendo Seu Primeiro Programa Concorrente em Go no Ubuntu

A linguagem de programação Go do Google existe desde 2009 e, em 2012, a linguagem alcançou seu status oficial v1.0. Durante esses anos, muita coisa mudou, incluindo como a linguagem é instalada. No início, não havia distribuições binárias oficiais e você tinha que compilar o Go a partir do código-fonte, que era o método recomendado, já que a linguagem estava mudando com frequência, ou usar um pacote pré-compilado para sua distribuição Linux. Naquela época, o suporte ao Windows era limitado, assim como o suporte para arquiteturas de CPU além da Intel.

As coisas melhoraram muito desde então. Para Linux, existem duas maneiras fáceis de instalar o Go. Baixe a versão binária oficial do Linux na página de downloads do Go ou opte por um pacote pré-compilado para sua distribuição Linux. A maneira mais fácil de instalar o Go no Ubuntu é usar apt-get:

sudo apt-get install golang

Uma vez que o Go esteja instalado, você pode começar a desenvolver programas. Um dos programas Go mais simples é o clássico “Hello World!”. Usando um editor de texto, crie um arquivo chamado “ hellomte.go “ com o seguinte código Go curto:

package main  
  
import "fmt"  
  
func main(){  
     fmt.Println("Hello Make Tech Easier!")  
}

Desde a v1.0 do Go, a necessidade de comandos de compilação e link individuais foi removida e os antigos comandos 8g e 8l foram substituídos pelo comando go.

Para executar hellomte.go, abra um terminal e mude o diretório para a pasta que contém o arquivo de código-fonte, em seguida, digite:

go run hellomte.go

Isso irá compilar e executar o programa Go, mas não produzirá um binário executável. Para criar um binário e depois executá-lo, use o comando go build:

go build hellomte.go  
./hellomte

O poder da concorrência

Uma das características definidoras da linguagem de programação Go é seu suporte à concorrência, que permite que um programa trabalhe com várias tarefas ao mesmo tempo. O paralelismo, que é semelhante à concorrência, permite que um programa execute muitas tarefas simultaneamente, mas a concorrência vai um passo além, pois permite que essas tarefas separadas se comuniquem e interajam. Como resultado, o Go permite que os programadores usem uma variedade de designs concorrentes diferentes, incluindo pools de trabalhadores, pipelines (onde uma tarefa acontece após outra) e tarefas de fundo síncronas ou assíncronas. A base dessa concorrência é a goroutine combinada com channels e a declaração select do Go.

Aqui está um programa Go simples que imprime uma string várias vezes usando uma goroutine concorrente:

package main  
  
import(  
"fmt"  
"time"  
)  
  
func say(s string){  
for i := 0; i < 5; i++ {  
        fmt.Println(s)  
}  
}  
  
func main(){  
go say("Hello Make Tech Easier!")  
    fmt.Println("Durma um pouco...")  
    time.Sleep(100 * time.Millisecond)  
}

A função say() apenas realiza um loop simples para imprimir a string (parâmetro s) cinco vezes. O interessante é como essa função é chamada. Em vez de apenas chamar say("Hello Make Tech Easier!"), a palavra-chave go é colocada na frente da chamada da função. Isso significa que a função será executada como uma tarefa separada. O restante da função main() então apenas dorme um pouco para dar tempo para a goroutine completar.

A saída pode te surpreender:

go-lang-concurrent

Como você pode ver, a função say() é executada como uma goroutine e enquanto está sendo configurada, o restante da função main() continua, imprimindo “Durma um pouco…” e depois indo dormir. Nesse momento, a goroutine está ativa e começa a imprimir a string cinco vezes. Finalmente, o programa termina uma vez que o limite de tempo foi alcançado.

Canais

As goroutines podem se comunicar usando canais. Um canal abre uma linha de comunicação entre duas partes diferentes de um programa Go. Normalmente, uma função será chamada como uma goroutine e se precisar enviar dados de volta (digamos, de uma operação de rede), pode usar um canal para passar esses dados. Se outra parte do programa Go estiver esperando por esses dados, ela ficará em espera até que os dados estejam prontos. Os canais são criados usando a função make() e podem ser passados como parâmetros para goroutines.

Considere este código:

package main  
  
import(  
"fmt"  
)  
  
func say(s string, c chan int){  
var i int  
for i = 0; i < 5; i++ {  
          fmt.Println(s)  
}  
     c <- i  
}  
  
func main(){  
     c := make(chan int)  
go say("Hello Make Tech Easier!", c)  
     sts := <- c  
     fmt.Println(sts)  
}

A função say() é muito semelhante ao primeiro exemplo, com a exceção de que o segundo parâmetro é um canal e que, após imprimir a string, o número de iterações será enviado pelo canal através da linha de código c <- i.

A função principal cria um canal, inicia a função say() como uma goroutine e então espera que os dados cheguem pelo canal, sts := <- c, antes de imprimir o resultado.

Conclusão

A linguagem Go progrediu significativamente nos últimos anos, se você não a olhou recentemente, talvez agora seja um bom momento!