GoLang: Explorando a Linguagem do Google



Em 2009 foi lançada oficialmente a linguagem de programação Go, a linguagem do Google. O projeto inicial da linguagem foi criado em 2007 por Robert Grisemer, Rob Pike e Ken Thompson. Go é uma linguagem muito semelhante a linguagem C e muitas vezes é mencionada como "C para o século XXI". Assim como C e C++, Go busca performance, mas diferente de ambas, Go também busca simplicidade. Por ser uma linguagem moderna, Go tem apenas 13 anos, na sua implementação foi possível agrupar muitas das evoluções computacionais que não existiam no tempo que linguagens como C foram criadas.


A linguagem propõe conciliar boas ideias de muitas outras linguagens e, como busca produtividade, também evita várias ideias que poderiam tornar o desenvolvimento mais complexo e não confiável. Go tem recursos e atributos de linguagens como C (imperativa), Java (orientada a objetos) e LISP (funcional) e apesar de ser uma linguagem multi-paradigma a concorrência e a imperatividade são os que predominam.


A concorrência nativa da linguagem faz com que ela seja uma ótima opção para criar programas que rodam em sistemas distribuídos e ferramentas para desenvolvedores. Além disso Go geralmente executa os programas mais rápido que algumas linguagens dinâmicas.



Concorrência vs Paralelismo


É importante não confundir a concorrência com o paralelismo. Todo processo paralelo também é concorrente, mas nem todo processo concorrente é paralelo. O conceito é o mesmo, mas a execução dos processos é diferente.

A concorrência é sobre lidar com muitas coisas ao mesmo tempo e o paralelismo é sobre fazer muitas coisas ao mesmo tempo.


Em sistemas que lidam com paralelismo temos duas ou mais tarefas sendo executadas ao mesmo tempo em núcleos diferentes, já em sistemas que lidam com concorrência, duas ou mais tarefas são enviadas para execução, porém essas tarefas vão concorrer umas com as outras por uma fatia do tempo de execução dos processadores.



Estrutura da Linguagem


Os tipos primitivos são quase os mesmos existentes na maioria das linguagens. Temos: int, string, float32, float64 e bool. E a instrução var é usada para declarar uma ou mais variáveis. Caso uma variável seja apenas declarada e não receba valor, como no exemplo abaixo, quando ela for usada em algum momento do código seu valor será o que é considerado como nulo pela linguagem (0 para inteiros, 0.0 para float e "" para strings).


Go disponibiliza um operador de declaração de varável (:= - short declaration operator) que só pode ser usado dentro do escopo de funções. Ele é usado para declarar e atribuir valores a variáveis. Caso seja necessário declarar variáveis fora desse escopo a instrução var deve ser usada.


Go trata unicode de modo nativo, portanto é capaz de processar textos em todas as línguas do mundo.

Os slices podem ser definidos informalmente como "arrays dinâmicos". Tanto o array quanto o slice em Go possuem duas propriedades, tamanho e capacidade e ambos estão intimamente ligados. A diferença entre os dois é que quando atingimos a capacidade máxima de um slice e tentamos adicionar mais um elemento, a linguagem dobra seu tamanho "automaticamente".

Em Go temos apenas um laço de repetição, o for, e dependendo de como usamos podemos ter um comportamento de um laço for como é comumente conhecido ou um de um laço while. Parênteses jamais são usados em torno dos componentes do loop, mas as chaves são obrigatórias, e a chave de abertura deve estar na mesma linha que o a instrução for (O mesmo é valido para os condicionais if e switch).


A instrução defer no Go atrasa a execução de uma função. No código abaixo a instrução defer fmt.Println("And IT") será executada apenas quando for identificado que não existe mais nada para executar dentro do main.


Além dessas, existem muitas outras particularidades da linguagem.

Usando concorrência em Go

Hoje os servidores web recebem e tratam milhares de requisições de clientes simultaneamente. A programação concorrente nunca foi tão importante quanto atualmente. Em Go é possível usar dois modos de programação concorrente, as gorrotinas e os canais. Vamos abordar nesse artigo somente as gorrotinas.

Cada atividade que executa de maneira concorrente é denominada gorrotina. Quando um programa inicia a única gorrotina existente é a que faz a chamada da função main (main goroutine). Novas gorrotinas podem ser criadas usando a instrução go.

No exemplo a seguir, o programa a seguir uma tarefa será executada muitas vezes para simular, o recebimento de muitas tarefas ao mesmo tempo:


Ao executar o programa sem o uso de concorrência, as "tarefas" serão executadas sequencialmente até que todas sejam concluídas e teremos a seguinte saída:


Adicionando a instrução go para indicar que queremos que as tarefas tenham um comportamento e sejam executadas de maneira concorrente teremos o seguinte código:



Porém ao executar o código teremos a seguinte saída:


Isso acontece porque quando usamos a instrução go para indicar que a tarefa será executada de maneira concorrente, estamos criando uma nova goroutine rodando em uma thread diferente da rotina principal (main goroutine) e esta termina muito mais rápido que a goroutine criada.

Para solucionar esse problema podemos adicionar um WaitGroup. O WaitGroup é um tipo de contador que bloqueia a execução de uma goroutine até que o contador se torne 0. Ele será usado para sincronizar a main goroutine com a nova rotina criada.

O WaitGroup tem três funções: Done(), Add() e Wait(). A função Done() informa o termino de uma tarefa e decrementa o contador interno. A função Add funciona como se fosse um "contador de rotinas" ele incrementa o contador interno (no nosso programas criamos apenas uma goroutine, mas caso tivéssemos criado 2 teríamos Add(2) e assim por diante). E a função Wait() serve como uma "sentinela" que aguarda as tarefas serem concluídas sincronizando a execução das novas rotinas criadas com a rotina principal, sem ele teríamos o mesmo resultado do código anterior.


Usando WaitGroup:





E dessa vez teremos a seguinte saída:


Na verdade, cada vez que o código for executado teremos uma saída diferente, pois agora, as tarefas estão competindo entre si para que sejam executadas pelo processador.











22 visualizações0 comentário

Posts recentes

Ver tudo