Conceitos de Go
Go avançado, do scheduler e do garbage collector do runtime a concorrência, generics e produção, medido no Go 1.27 e baseado na documentação oficial, em livros e em papers, um conceito de cada vez.
Scheduler & GC
O Escalonador de Goroutines: G, M e P
O escalonador do Go a partir do cabeçalho de runtime/proc.go e do design doc do Vyukov, conferido com programas no Go 1.27; G, M e P; o slot runnext que roda primeiro a goroutine mais nova (e o -race embaralhando isso); filas locais e global e roubo de trabalho no GODEBUG=schedtrace; preempção assíncrona por SIGURG contra asyncpreemptoff=1 (um sleep de 1 ms virando 302 ms, uma parada do GC esperando o laço); o P repassado 32 a 54 µs depois de um read(2) bloqueante; 100 reads bloqueantes custando 100 threads enquanto o netpoller não custa nenhuma; e as métricas /sched/*, incluindo o nome das notas da 1.26 que não existe.
GOMAXPROCS em Contêineres
O GOMAXPROCS ciente de contêiner do Go 1.25, separando o que foi medido no macOS com Go 1.27 do que vem da doc e do código do runtime; a regra (mínimo entre CPUs, afinidade e o teto arredondado para cima do limite do cgroup, piso de 2, request ignorado), os arquivos cpu.max e de quota do cfs lidos só do cgroup folha, as atualizações periódicas pelo sysmon e pela goroutine GOMAXPROCS updater, as sobrescritas e o SetDefaultGOMAXPROCS com suas pausas stop-the-world, a linha go do go.mod desligando tudo (e um bloco godebug religando), um contador do godebug que nunca se mexe, e uma carga CPU-bound em malha aberta mostrando vazão travada e segundos de latência abaixo do paralelismo necessário, com o throttling deixado para a documentação.
O Garbage Collector do Go: GOGC e GOMEMLIMIT
O coletor mark-sweep tricolor, concorrente e sem movimentação do Go, a partir da proposta do write barrier híbrido e do keynote do ISMM 2018; uma linha de GODEBUG=gctrace=1 lida campo a campo; uma carga fixa medida no Go 1.27 com GOGC 50, 100, 200 e off, em que cada dobra corta pela metade os ciclos e a CPU de GC e dobra a folga de memória; GOMEMLIMIT como teto suave com GOGC=off (11 ciclos em vez de 62 a 64) e os sufixos que ele rejeita; o death spiral com o heap vivo perto e acima do limite (30 vezes a CPU de GC, memória passando do limite, uma lentidão de 6x que o limitador de 50% de CPU não evita); e os controles em runtime/metrics e runtime/debug.
Green Tea GC
O Green Tea, algoritmo de marcação padrão desde o Go 1.26, que enfileira spans em vez de objetos e varre de uma vez os objetos marcados de cada span; os dois conjuntos de bits por span e a janela de 16 a 512 bytes lidos no código do runtime; o opt-out GOEXPERIMENT=nogreenteagc, que ainda compila no Go 1.27.0 apesar das notas da 1.26; CPU de GC por ciclo medida em arm64 com e sem Green Tea em três formatos de heap (50 a 58% a menos num grafo de objetos pequenos, empate numa cadeia longa, 26 a 38% a mais em objetos de 2 KiB) e num laço guiado por alocação (cerca de 50% a menos); e a comparação com os 10 a 40% das notas de lançamento.
Concurrency
Modelo de Memória do Go e sync/atomic
O modelo de memória do Go revisado em 2022 com happens-before e as arestas synchronized-before de channels, mutexes, sync.Once, WaitGroup e atomics, DRF-SC, testes litmus de store buffering e message passing mostrando reordenação real no arm64, o compilador apagando escritas de um loop com race, o que um programa com race ainda garante (valores de uma palavra sem out-of-thin-air) e o que não garante (interface rasgada até o SIGSEGV), atomics sequencialmente consistentes e tipados (atomic.Int64, atomic.Pointer[T]), os avisos do vet e o double-checked init quebrado contra sync.OnceValue e atomic.Pointer, com relatórios reais do -race.
Padrões Avançados de Concorrência em Go
Pipelines com cancelamento por context (adaptados do artigo de pipelines do blog do Go), fan-out e fan-in e a ordem perdida, paralelismo limitado com errgroup.SetLimit contra semaphore e channel com buffer medindo pico de tarefas e de goroutines, semáforo com peso e fila FIFO, cancelamento no primeiro erro com errgroup.WithContext e context.Cause, singleflight com 100 chamadores e uma execução, o context do primeiro chamador vazando para todos e context.WithoutCancel, e sync.WaitGroup.Go (Go 1.25) com o analisador waitgroup do vet e o go fix.
Context: Árvores de Cancelamento, Deadlines e Causas
A árvore de contexts e o cancelamento síncrono medido até 100.000 filhos, a goroutine por filho sob um Context próprio, DeadlineExceeded versus Canceled, WithCancelCause, WithTimeoutCause e context.Cause, AfterFunc e sua função stop destravando a leitura de um net.Conn, WithoutCancel para trabalho depois da resposta, colisão de chaves em WithValue e o custo linear da busca, as mensagens do lostcancel do go vet e o heap que um cancel esquecido segura, o que o servidor vê quando o deadline do cliente HTTP estoura e por que um context não deve ficar dentro de uma struct.
Bugs de Concorrência: Races e Deadlocks em Código Go Real
A taxonomia bloqueante versus não bloqueante e memória compartilhada versus troca de mensagens de 171 bugs reais (ASPLOS 2019) e as causas de 1.011 races corrigidas na Uber (PLDI 2022), reproduzidas com relatórios reais do -race, fatal errors do runtime e mensagens do go vet: captura da variável de loop com go 1.21 versus go 1.22, escrita concorrente em map, append em slice sem lock, WaitGroup.Add dentro da goroutine e WaitGroup.Go, um envio que ninguém recebe e o vazamento que o runtime nunca reporta, um mutex copiado por valor, o custo medido do race detector e GCatch e GFix como detecção estática.
Detecção de Vazamento de Goroutines: o Perfil goroutineleak e o goleak
O perfil goroutineleak, GA no Go 1.27 em runtime/pprof e em /debug/pprof/goroutineleak, como o GC prova por alcançabilidade que uma goroutine bloqueada nunca acorda (Golf, ASPLOS 2025), os pontos cegos medidos com primitivas alcançáveis por globais, por goroutines que dormem e por variável capturada na closure, a comparação com o perfil goroutine e com go.uber.org/goleak em testes, e o custo medido de um ciclo de detecção, inclusive o pior caso em cadeia.
Testes Determinísticos com testing/synctest
Bolhas do testing/synctest (GA no Go 1.25) com relógio falso que só avança quando toda goroutine está durably blocked, o que conta como bloqueio durável e por que mutex e I/O congelam o relógio, synctest.Wait como ponto de sincronização para o race detector, retry, deadline e expiração de cache de 23 minutos falsos medidos em microssegundos, o flake de timers no mesmo instante corrigido por synctest.Sleep (Go 1.27), httptest.NewTestServer (Go 1.27) com rede em memória, e os panics e fatal errors medidos ao quebrar cada regra.