← Voltar para o blog

Go 1.14: Novidades e Recursos

Descubra as principais novidades do Go 1.14, incluindo novos recursos, melhorias de performance e mudancas na biblioteca padrao.

Go 1.14: Um Olhar Detalhado nas Novidades

A versão 1.14 da linguagem Go foi lançada em 25 de fevereiro de 2020, trazendo consigo uma série de melhorias e adições que impactam tanto o desempenho quanto a usabilidade da linguagem. Esta versão foca em aprimorar o suporte a módulos, otimizar o desempenho do garbage collector e introduzir funcionalidades que facilitam o desenvolvimento concorrente. Este artigo explora as principais novidades, as mudanças na biblioteca padrão e fornece um guia prático para a atualização.

Gerenciamento de Módulos Aprimorado

O Go 1.14 solidifica o suporte a módulos como o método padrão para gerenciamento de dependências. Embora os módulos tenham sido introduzidos em versões anteriores, o Go 1.14 remove a necessidade de configurar variáveis de ambiente como GO111MODULE=on para habilitar o uso de módulos fora do $GOPATH. Agora, o Go assume que você está usando módulos se encontrar um arquivo go.mod no diretório atual ou em um diretório pai.

Modo Vendor Ativado por Padrão

Uma das mudanças mais significativas é a ativação padrão do modo “vendor” quando um diretório vendor está presente no diretório raiz do módulo. Isso significa que o Go irá procurar por dependências dentro do diretório vendor antes de recorrer ao cache de módulos globais ou a outros repositórios.

Essa mudança simplifica a reprodução de builds e garante que as dependências usadas durante o desenvolvimento sejam as mesmas usadas em produção. Para utilizar o modo vendor, basta ter um diretório vendor válido no seu projeto, criado geralmente através do comando go mod vendor.

go mod vendor

Após executar o comando, um diretório vendor será criado contendo todas as dependências declaradas no seu arquivo go.mod. Durante a compilação, o Go irá priorizar os pacotes presentes neste diretório.

Compatibilidade Aprimorada com Ferramentas de Terceiros

O Go 1.14 também introduz melhorias na compatibilidade com ferramentas de terceiros que interagem com os módulos Go. Essas melhorias visam facilitar a integração com IDEs, analisadores estáticos e outras ferramentas que dependem da análise da estrutura do módulo.

Garbage Collector Mais Eficiente

O garbage collector (GC) do Go passou por otimizações significativas no Go 1.14, resultando em menor latência e maior utilização da CPU. Essas melhorias são especialmente notáveis em aplicações com grandes quantidades de alocação e desalocação de memória.

Coleta de Memória Não-Cooperativa

Uma das principais mudanças é a introdução da coleta de memória não-cooperativa. Em versões anteriores, o GC dependia fortemente das goroutines para cooperar na coleta de memória. No Go 1.14, o GC pode interromper as goroutines em pontos seguros para realizar a coleta de memória, reduzindo a latência e melhorando o desempenho geral.

Essa abordagem reduz a dependência da cooperação das goroutines e permite que o GC trabalhe de forma mais autônoma, especialmente em cenários onde algumas goroutines podem estar em execução por longos períodos sem liberar o processador.

Melhorias na Escalonabilidade

O Go 1.14 também inclui melhorias na escalabilidade do GC em sistemas com muitos núcleos de CPU. O GC agora consegue utilizar mais eficientemente os recursos disponíveis, resultando em menor tempo de pausa e maior taxa de transferência.

Essas melhorias beneficiam especialmente aplicações de alta performance que exigem baixa latência e alta escalabilidade.

Goroutines Preemptivas Baseadas em Sinais

Uma das adições mais significativas no Go 1.14 é o suporte a goroutines preemptivas baseadas em sinais. Essa funcionalidade resolve um problema de longa data na linguagem Go: goroutines que realizam loops infinitos ou operações de longa duração sem fazer chamadas de função podem bloquear o scheduler do Go, impedindo que outras goroutines sejam executadas.

Resolvendo o Problema de Goroutines Bloqueadas

Em versões anteriores do Go, se uma goroutine entrasse em um loop infinito sem fazer chamadas de função (por exemplo, sem chamar time.Sleep ou enviar/receber dados em um canal), o scheduler do Go não conseguiria interromper essa goroutine para executar outras. Isso poderia levar a problemas de starvation, onde outras goroutines seriam impedidas de serem executadas.

O Go 1.14 introduz um mecanismo que permite ao scheduler enviar um sinal para uma goroutine que está em execução por um período prolongado sem fazer chamadas de função. Esse sinal força a goroutine a entrar em um ponto seguro, onde o scheduler pode interrompê-la e dar a outras goroutines a chance de serem executadas.

Impacto no Desenvolvimento Concorrente

Essa mudança tem um impacto significativo no desenvolvimento concorrente em Go, tornando a linguagem mais robusta e previsível em cenários onde goroutines podem potencialmente bloquear o scheduler.

Embora essa funcionalidade seja ativada por padrão, ela ainda é considerada experimental e pode ser desabilitada através da variável de ambiente GODEBUG=preemptoff=1. No entanto, a maioria dos usuários não precisa se preocupar em desativá-la, pois ela melhora a estabilidade e o desempenho do scheduler.

Exemplo Prático

O exemplo abaixo demonstra como uma goroutine pode bloquear o scheduler em versões anteriores do Go e como o Go 1.14 resolve esse problema:

package main

import (
	"fmt"
	"runtime"
	"time"
)

func main() {
	runtime.GOMAXPROCS(1) // Garante que apenas um núcleo seja usado
	go func() {
		for {
			// Loop infinito sem chamadas de função
		}
	}()

	time.Sleep(100 * time.Millisecond) // Espera um pouco para a goroutine iniciar

	fmt.Println("Hello from main!") // Esta linha pode não ser executada em versões anteriores do Go
}

Em versões anteriores do Go, a goroutine que contém o loop infinito pode impedir que a goroutine principal imprima “Hello from main!”. No Go 1.14, o scheduler consegue interromper a goroutine em loop e permitir que a goroutine principal seja executada.

Mudanças na Biblioteca Padrão

O Go 1.14 também introduz algumas mudanças e adições à biblioteca padrão.

Pacote embed (experimental)

O Go 1.14 introduz um novo pacote experimental chamado embed. Este pacote permite que arquivos sejam incorporados diretamente no executável Go durante a compilação. Isso é útil para incluir arquivos de configuração, templates HTML, arquivos estáticos e outros recursos que sua aplicação precisa.

Para usar o pacote embed, você precisa adicionar uma diretiva especial no seu código Go:

//go:embed file.txt
var fileContent string

Neste exemplo, o conteúdo do arquivo file.txt será incorporado na variável fileContent durante a compilação. O pacote embed oferece várias opções para trabalhar com arquivos e diretórios incorporados, incluindo a capacidade de iterar sobre os arquivos em um diretório.

Exemplo:

Suponha que você tenha um arquivo chamado version.txt com o número da versão do seu programa. Você pode incorporá-lo no seu código da seguinte forma:

package main

import (
	"embed"
	"fmt"
)

//go:embed version.txt
var version string

func main() {
	fmt.Println("Version:", version)
}

Durante a compilação, o conteúdo do arquivo version.txt será incorporado na variável version. Isso facilita a distribuição de aplicações com seus recursos incorporados.

Considerações:

  • O pacote embed é experimental e sua API pode mudar em versões futuras do Go.
  • A incorporação de arquivos grandes pode aumentar o tamanho do seu executável.

Pacote os/signal

O pacote os/signal recebeu algumas melhorias para facilitar o tratamento de sinais do sistema operacional.

Melhorias de Performance

Além das otimizações no garbage collector, o Go 1.14 também inclui outras melhorias de performance em diversas áreas da linguagem.

Desempenho Aprimorado em Funções defer

A execução de funções defer foi otimizada, resultando em menor overhead e maior desempenho. As funções defer são usadas para garantir que um bloco de código seja executado quando a função circundante retorna, independentemente de como a função retorna (normalmente ou devido a um panic).

Otimizações no Inlining

O compilador Go agora realiza inlining de forma mais agressiva, substituindo chamadas de função por seu corpo diretamente no código. Isso pode reduzir o overhead de chamadas de função e melhorar o desempenho geral.

Como Atualizar para o Go 1.14

A atualização para o Go 1.14 é um processo relativamente simples. Você pode baixar a nova versão do site oficial do Go (https://go.dev/dl/) e seguir as instruções de instalação.

Após a instalação, você pode verificar se a atualização foi bem-sucedida executando o seguinte comando:

go version

Este comando deve imprimir a versão do Go instalada, confirmando que você está executando o Go 1.14.

Considerações Importantes

  • Teste seus projetos: Antes de atualizar seus projetos para o Go 1.14 em produção, é importante testá-los exaustivamente para garantir que não haja problemas de compatibilidade.
  • Verifique as dependências: Certifique-se de que todas as suas dependências são compatíveis com o Go 1.14. Se você estiver usando módulos Go, o comando go mod tidy pode ajudar a identificar e resolver problemas de dependência.
  • Leia as notas de lançamento: Consulte as notas de lançamento do Go 1.14 (https://go.dev/doc/go1.14) para obter uma lista completa de todas as mudanças e correções.

Conclusão

O Go 1.14 representa um avanço significativo na evolução da linguagem Go. As melhorias no gerenciamento de módulos, no garbage collector e no scheduler tornam o Go uma linguagem ainda mais poderosa e eficiente para o desenvolvimento de aplicações modernas. A introdução do pacote embed e outras mudanças na biblioteca padrão também facilitam o desenvolvimento e a distribuição de aplicações Go. Ao atualizar para o Go 1.14, você pode se beneficiar dessas melhorias e garantir que seus projetos estejam usando a versão mais recente e otimizada da linguagem. A adoção dos módulos como padrão, juntamente com as melhorias de desempenho, solidificam o Go como uma escolha excelente para uma vasta gama de aplicações, desde microsserviços até ferramentas de linha de comando.