Para processar consultas de CPF em paralelo com goroutines em Go, utilize sync.WaitGroup para lotes simples, um channel como semáforo para controlar a concorrência máxima e errgroup quando precisar de propagação de erros e cancelamento coordenado. Cada goroutine consome apenas alguns kilobytes de memória, permitindo processar centenas de CPFs simultaneamente com latência próxima à de uma única consulta sequencial.
Introdução
Go foi projetada desde o início para concorrência, e as goroutines são a primitiva mais poderosa da linguagem para esse propósito. Processar centenas ou milhares de consultas de CPF em paralelo usando goroutines é extremamente eficiente: cada goroutine consome apenas alguns kilobytes de memória, e o scheduler do Go distribui o trabalho automaticamente entre os cores disponíveis.
Goroutines vs. threads tradicionais
Goroutines oferecem vantagens significativas sobre threads do sistema operacional.
| Característica | Goroutine | Thread do SO |
|---|---|---|
| Memória inicial | ~2KB | ~1MB |
| Criação | Microssegundos | Milissegundos |
| Troca de contexto | ~200ns | ~1000ns |
| Limite prático | Milhões | Milhares |
| Gerenciamento | Runtime do Go | Sistema operacional |
| Comunicação | Channels (seguro) | Mutexes (propenso a erros) |
Goroutines são leves -- é possível criar milhares sem impacto significativo na memória.
Channels são seguros -- permitem comunicação entre goroutines sem necessidade de locks manuais.
Scheduler eficiente -- o runtime do Go multiplexa goroutines em threads do SO automaticamente.
Padrão básico com WaitGroup
A abordagem mais simples usa sync.WaitGroup para aguardar todas as goroutines completarem.
package main
import (
"encoding/json"
"fmt"
"net/http"
"os"
"sync"
"time"
)
type ResultadoCPF struct {
CPF string `json:"cpf"`
Sucesso bool `json:"sucesso"`
Nome string `json:"nome,omitempty"`
Erro string `json:"erro,omitempty"`
}
type APIResponse struct {
Success bool `json:"success"`
Data struct {
Name string `json:"name"`
} `json:"data"`
}
func consultarCPF(cpf string, apiKey string) ResultadoCPF {
url := fmt.Sprintf("https://api.cpfhub.io/cpf/%s", cpf)
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("x-api-key", apiKey)
client := &http.Client{Timeout: 10 * time.Second}
resp, err := client.Do(req)
if err != nil {
return ResultadoCPF{CPF: cpf, Sucesso: false, Erro: err.Error()}
}
defer resp.Body.Close()
var resultado APIResponse
json.NewDecoder(resp.Body).Decode(&resultado)
if resultado.Success {
return ResultadoCPF{CPF: cpf, Sucesso: true, Nome: resultado.Data.Name}
}
return ResultadoCPF{CPF: cpf, Sucesso: false, Erro: "nao encontrado"}
}
func consultarLoteSimples(cpfs []string, apiKey string) []ResultadoCPF {
var wg sync.WaitGroup
resultados := make([]ResultadoCPF, len(cpfs))
for i, cpf := range cpfs {
wg.Add(1)
go func(idx int, c string) {
defer wg.Done()
resultados[idx] = consultarCPF(c, apiKey)
}(i, cpf)
}
wg.Wait()
return resultados
}
func main() {
apiKey := os.Getenv("CPFHUB_API_KEY")
cpfs := []string{"12345678901", "98765432100", "11122233344"}
inicio := time.Now()
resultados := consultarLoteSimples(cpfs, apiKey)
duracao := time.Since(inicio)
for _, r := range resultados {
fmt.Printf("CPF: %s | Sucesso: %v | Nome: %s\n", r.CPF, r.Sucesso, r.Nome)
}
fmt.Printf("Duracao: %v\n", duracao)
}
Controle de concorrência com semáforo
Para evitar sobrecarregar a API, use um channel como semáforo para limitar goroutines simultâneas.
func consultarLoteControlado(cpfs []string, apiKey string, maxConcorrencia int) []ResultadoCPF {
var wg sync.WaitGroup
resultados := make([]ResultadoCPF, len(cpfs))
semaforo := make(chan struct{}, maxConcorrencia)
for i, cpf := range cpfs {
wg.Add(1)
go func(idx int, c string) {
defer wg.Done()
semaforo <- struct{}{} // Adquirir slot
defer func() { <-semaforo }() // Liberar slot
resultados[idx] = consultarCPF(c, apiKey)
}(i, cpf)
}
wg.Wait()
return resultados
}
| Concorrência | 100 CPFs | 1.000 CPFs | 10.000 CPFs |
|---|---|---|---|
| 1 (sequencial) | ~20s | ~200s | ~2000s |
| 10 | ~2s | ~20s | ~200s |
| 50 | ~0.4s | ~4s | ~40s |
| 100 | ~0.2s | ~2s | ~20s |
Padrão worker pool com channels
O padrão worker pool distribui trabalho entre um número fixo de goroutines trabalhadoras.
func workerPool(cpfs []string, apiKey string, numWorkers int) []ResultadoCPF {
type tarefa struct {
indice int
cpf string
}
tarefas := make(chan tarefa, len(cpfs))
resultadosChan := make(chan ResultadoCPF, len(cpfs))
// Iniciar workers
var wg sync.WaitGroup
for w := 0; w < numWorkers; w++ {
wg.Add(1)
go func() {
defer wg.Done()
for t := range tarefas {
resultado := consultarCPF(t.cpf, apiKey)
resultadosChan <- resultado
}
}()
}
// Enviar tarefas
for i, cpf := range cpfs {
tarefas <- tarefa{indice: i, cpf: cpf}
}
close(tarefas)
// Aguardar workers e fechar canal de resultados
go func() {
wg.Wait()
close(resultadosChan)
}()
// Coletar resultados
resultados := make([]ResultadoCPF, 0, len(cpfs))
for r := range resultadosChan {
resultados = append(resultados, r)
}
return resultados
}
Errgroup para tratamento de erros
O pacote errgroup oferece propagação de erros e cancelamento coordenado entre goroutines. A recomendação da OWASP para processamento seguro de dados pessoais inclui garantir que falhas parciais não deixem dados inconsistentes — o errgroup facilita esse controle ao cancelar o contexto assim que um erro crítico ocorre.
import (
"context"
"golang.org/x/sync/errgroup"
)
func consultarLoteComErrgroup(ctx context.Context, cpfs []string, apiKey string) ([]ResultadoCPF, error) {
resultados := make([]ResultadoCPF, len(cpfs))
g, ctx := errgroup.WithContext(ctx)
g.SetLimit(20) // Máximo 20 goroutines simultâneas
for i, cpf := range cpfs {
idx := i
c := cpf
g.Go(func() error {
select {
case <-ctx.Done():
return ctx.Err()
default:
resultados[idx] = consultarCPF(c, apiKey)
if resultados[idx].Erro == "rate_limit" {
return fmt.Errorf("rate limit excedido para CPF %s", c)
}
return nil
}
})
}
if err := g.Wait(); err != nil {
return resultados, fmt.Errorf("erro no processamento: %w", err)
}
return resultados, nil
}
SetLimit -- define o número máximo de goroutines concorrentes.
Context cancelável -- se uma goroutine falhar com erro crítico, as demais podem ser canceladas.
Propagação de erros -- o primeiro erro é retornado ao chamador após todas as goroutines completarem.
Perguntas frequentes
Quantas goroutines simultâneas devo usar para consultar a API de CPF?
O número ideal depende do seu volume e do plano contratado. Um bom ponto de partida é 10 a 20 goroutines simultâneas, o que já reduz o tempo de processamento de lotes em até 95% em relação à abordagem sequencial. Aumente gradualmente monitorando a latência de resposta da API e os erros de timeout.
Como evitar erros de timeout ao processar lotes grandes de CPF?
Configure um timeout explícito no http.Client (recomendado: 10 segundos para absorver os ~900ms de latência com margem de segurança) e use o padrão de semáforo ou errgroup.SetLimit para não disparar todas as goroutines ao mesmo tempo. Para lotes acima de 1.000 CPFs, processe em chunks com pausas entre eles.
O plano gratuito da CPFHub.io suporta processamento em lote?
Sim. O plano gratuito oferece 50 consultas por mês, sem bloqueio ao atingir o limite — consultas adicionais são cobradas a R$0,15 cada. Para testes de carga e desenvolvimento, o plano gratuito é suficiente para validar a implementação das goroutines antes de escalar para o plano Pro (1.000 consultas/mês por R$149).
Qual padrão de concorrência é mais adequado para processar CPFs em produção?
O worker pool com channels é o padrão mais robusto para produção: controla o número exato de goroutines ativas, reutiliza workers em vez de criar novos a cada tarefa e facilita o monitoramento. O errgroup é preferível quando você precisa cancelar todo o lote ao detectar um erro crítico.
Conclusão
As goroutines de Go oferecem uma forma elegante e eficiente de processar consultas de CPF em paralelo. Desde o padrão simples com WaitGroup até o worker pool com channels e o errgroup para tratamento coordenado de erros, Go fornece primitivas poderosas para cada cenário de concorrência. A chave é escolher o nível de concorrência adequado ao rate limit da API e monitorar métricas de performance para ajustar os parâmetros.
Cadastre-se em cpfhub.io — 50 consultas mensais gratuitas, sem cartão de crédito — e comece a processar lotes de CPF com alta performance usando goroutines hoje mesmo.
CPFHub.io
Pronto para integrar a API?
50 consultas gratuitas para testar agora. Sem cartão de crédito. Acesso imediato à documentação.
Sobre a redação
Redação CPFHub.io
Time editorial especializado em APIs de CPF, identidade digital e compliance no mercado brasileiro. Produzimos guias técnicos, análises regulatórias e tutoriais sobre LGPD e KYC para desenvolvedores e líderes de produto.



