Google Go: Primeiros passos e exemplos

Semana passada o Google anunciou que disponibilizou uma nova linguagem de programação chamada Go. Como sempre, cada novo lançamento do Google vem recheado de comentários “O Google vai dominar o mundo” e “O Google será a nova Microsoft”.

Logotipo Go

Fiquei curioso e resolvi fazer alguns testes nessa nova linguagem. Aqui eu apresento o passo-a-passo do que fiz para instalar e implementar 3 exemplos (hello world, programação concorrente e servidor web).

Instalando as ferramentas da Go

Se você é um usuário Windows, infelizmente ainda não tem como utilizar essa linguagem nesse sistema operacional, pois ela só foi liberada para Linux e Mac OS X. Neste artigo mostro os passos que fiz no Ubuntu 9.04 e, caso eles não funcionem com você, é possível ter mais informações no site oficial.

O projeto Go utiliza o repositório Mercurial para seus códigos-fonte, por isso se você não tem esse software instalado siga esses passos:

sudo apt-get install python-setuptools python-dev
sudo easy_install mercurial

Com o Mercurial instalado, o próximo passo é definir as seguintes variáveis de ambiente (sinta-se à vontade para alterar os caminhos dos diretórios):

export GOROOT=$HOME/go
export GOARCH=386
export GOOS=linux
export GOBIN=$GOROOT/bin
export PATH=$PATH:$GOBIN

Caso você esteja rodando um sistema 64 bits defina o valor de GOARCH como “amd64″ (veja mais detalhes sobre cada variável de ambiente no site oficial). Para que você não precise toda vez definir essas variáveis, é possível adicioná-las no arquivo .bashrc.

Agora faça o clone do repositório:

hg clone -r release https://go.googlecode.com/hg/ $GOROOT

Para compilar o Go você precisará do GCC, bibliotecas C padrão, o parser generator Bison, comando make e o editor ed instalado. Para isso, execute:

sudo apt-get install bison gcc libc6-dev ed make

Agora compile:

cd $GOROOT/src
$ ./all.bash

Se tudo deu certo irá aparecer o seguinte:

--- cd ../test
N known bugs; 0 unexpected bugs

Com as ferramentas instaladas, agora vamos aos exemplos.

Exemplo1: Hello world

Abra seu editor de texto preferido e crie o arquivo hello.go:

package main

import "fmt"

func main() {
   fmt.Printf("hello, world")
}

Download de hello.go

Para cada plataforma um compilador e linker diferente é utilizado:

  • amd64: 6g (compilador) / 6l (linker)
  • 386: 8g (compilador) / 8l (linker)
  • arm: 5g (compilador) / 8l (linker)

Aqui mostratei como compilar e “linkar” o código em 386:

8g hello.go
8l -o hello hello.8

Agora rode “./hello” e deverá ser impresso na tela “hello, world”.

Exemplo 2: Programação concorrente

Uma das vantagens que o Google anunciou dessa linguagem é o suporte mais simples a programação para vários núcleos. Para testar isso resolvi fazer um programa de cálculo do valor de PI aproximado através da série de Gregory, assim como fiz em um artigo anterior sobre Java.

Fórmula para cálculo PI

Abaixo está o código de pi.go:

package main

import (
 "fmt";
 "math";
)

func main() {
 //cria um canal com 4 buffers de float64
 c := make(chan float64, 4);

 //divide o calculo do PI em 4 partes que podem rodar independente
 go calcular_valor_parcial_pi(1.0, 1000000, c);
 go calcular_valor_parcial_pi(1000001, 2000000, c);
 go calcular_valor_parcial_pi(2000001, 3000000, c);
 go calcular_valor_parcial_pi(3000001, 4000000, c);

 //recebe do canal a resposta das 4 execucoes do calculo
 //a ordem que elas foram finalizadas nao importa
 valor_parcial := <-c;
 valor_parcial += <-c;
 valor_parcial += <-c;
 valor_parcial += <-c;

 //o valor final do pi se da pelo multiplicacao por 4
 pi := 4.0 * valor_parcial;

 //imprime valor de pi calculado na tela
 fmt.Printf("pi = %f n", pi);
}

func calcular_valor_parcial_pi(inicio float64, fim float64, c chan float64) {
 var valor float64 = 0.0;

 i := inicio;

 for i < fim {
 valor += math.Pow(-1.0, i + 1.0) / (2.0 * i - 1.0) ;
 i++;
 }

 //coloca no canal qual a resposta do valor parcial a ser calculado
 c <- valor;
}

Download de pi.go

Como pode ser visto, é muito simples criar uma aplicação que utilize o potencial dos processadores de múltiplos núcleos. É possível utilizar “go routines” quando se deseja rodar algo de forma assíncrona. Para isso, basta adicionar a palavra reservada “go” antes da chamada de um método (linhas 13, 14, 15 e 16). Como neste caso era necessário realizar a leitura e sincronização dos dados, utilizei um channel que foi criado na linha 10 através de make. O primeiro parâmetro é o tipo de dado do canal e o segundo o tamanho do buffer.

Na linha 43 é adicionado no channel o valor parcial calculado pela a chamada do método. Este, por sua vez, é lido nas linhas 20, 21, 22 e 23.

Simples, não? Porém nos testes que realizei em uma máquina dual core apenas foi utilizado 1 dos núcleos. Provavelmente é alguma limitação da versão disponível atualmente, pois segui a documentação do site da linguagem para essa implementação.

Exemplo 3: Servidor web

Também resolvi testar o atendimento de requisições HTTP através da Go. A seguir o código de uma aplicação que roda na porta 1234 e exibe algumas informações básicas do browser e da requisição.

package main

import (
 "http";
 "io";
)

func main() {
 //define o endereço e a função que trata as requisições
 http.Handle("/teste_go", http.HandlerFunc(RequestHandler));

 //aguarda conexão na porta 1234
 err := http.ListenAndServe(":1234", nil);

 //se aconteceu algum erro
 if err != nil {
 panic("Erro: ", err.String());
 }
}

func RequestHandler(c *http.Conn, req *http.Request) {
 //monta uma string com alguns parametros da requisicao
 str :=  "<b>Protocol:</b> " + req.Proto + "<br/>" +
 "<b>Method:</b> " + req.Method + "<br/>" +
 "<b>User-Agent:</b> " + req.UserAgent;

 //escreve string como resposta
 io.WriteString(c, str);
}

Download de web.go

Com o código compilado e rodando acesse http://localhost:1234/teste_go no seu browser.

Servidor web em Go

Conclusão

É difícil saber se uma nova linguagem será amplamente aceita e utilizada pela comunidade, por mais que tenha o Google por trás. Sem dúvida a Go possui muitas funcionalidades interessantes, mas o suporte a ponteiros e o fato de não rodar sobre uma máquina virtual podem definí-la como de baixo nível (em relação a Java e C#, por exemplo). Quem já programou em C++ pode ver na Go uma boa opção, já que ao contrário de C++ ela possui garbage collector e suporte fácil a programação concorrente.

Se você quiser estudar mais essa nova linguagem acesse seu site oficial e veja estes links de referência: