Como o Golang trabalha com goroutines por baixo dos panos.

Em Go, goroutines são tarefas leves gerenciadas pelo runtime, não diretamente pelo kernel.
Modelo M : P : G
- G (Goroutine): unidade de execução (função + stack pequena e dinâmica).
- M (Machine): uma thread do SO (ex.: pthread).
- P (Processor): contexto lógico do scheduler (fila local, cache, estado).
- Um M só executa G se estiver associado a um P.
- GOMAXPROCS define quantos Ps podem executar código Go em paralelo.
Memória: Stack e Heap
Stack (pilha): memória local de chamadas de função (parâmetros, variáveis locais, frames).
Em goroutines, começa pequena e cresce/encolhe sob demanda (stack grow/shrink).
Heap: memória para dados que precisam viver além do escopo imediato da função ou são compartilhados. É gerenciada pelo garbage collector (GC). Regra prática: dados de vida curta tendem a ficar na stack; dados que “escapam” vão para o heap (escape analysis do compilador).
Filas: local e global
Fila local (por P): destino principal de novas goroutines. Vantagem: menos lock e melhor localidade de cache.
Fila global (runtime): usada para balanceamento, overflow e casos especiais.
Escalonamento (resumo)
Um M+P pega G da fila local (caminho mais comum). Se estiver vazia, tenta fila global e/ou work stealing (roubar trabalho de outro P). Sem trabalho, o M pode estacionar.
Thread do SO vs Goroutine
Thread do SO (M): mais pesada, criada pelo sistema operacional.
Goroutine (G): leve; é possível ter milhares ou milhões. O runtime multiplexa muitas Gs sobre poucas Ms.
Por baixo dos panos
Syscall bloqueante: se uma G bloqueia, o runtime tenta liberar o P para outro M.
Netpoller: I/O de rede não bloqueante (epoll/kqueue etc.) acorda goroutines prontas.
Preempção: o scheduler interrompe goroutines longas para manter fairness.
0 comentários