(+351) 21 24 10006  ·  info@bconcepts.pt
Carnaxide, Lisboa

Como fazer chamadas paralelas a uma API em Python

João Barros 07 de July de 2026 4 min de leitura

Quando um programa precisa de chamar uma API dezenas ou centenas de vezes — por exemplo, para alimentar um dashboard ou recolher dados de vários endpoints —, fazê-lo uma chamada de cada vez torna-se muito lento. As chamadas paralelas a uma API em Python resolvem esse problema: em vez de esperar que cada pedido termine antes de começar o seguinte, enviamos vários ao mesmo tempo e o tempo total cai drasticamente.

Pré-requisitos

  • Python 3.8 ou superior instalado.
  • Saber fazer um pedido simples com requests ou httpx.
  • Um terminal para instalar pacotes com pip.
  • Vontade de experimentar: vamos usar a API pública de testes jsonplaceholder.typicode.com.

Passo 1: Perceber porque as chamadas sequenciais são lentas

Imagina que precisas de ir buscar 20 tarefas a uma API. Com um ciclo normal, cada pedido só começa quando o anterior termina. Se cada um demora cerca de 0,2 segundos, o total ronda os 4 segundos — e cresce à medida que aumentas o número de pedidos.

import time, httpx

inicio = time.perf_counter()
with httpx.Client() as cliente:
    for i in range(1, 21):
        r = cliente.get(f"https://jsonplaceholder.typicode.com/todos/{i}")
        r.json()
print(f"Sequencial: {time.perf_counter() - inicio:.2f} s")

O problema não é o teu computador estar ocupado: ele está quase sempre à espera da resposta da rede. É esse tempo morto, em que nada acontece, que vamos aproveitar para adiantar outros pedidos.

Passo 2: Instalar o httpx

O httpx é um cliente HTTP moderno que funciona de forma síncrona (como o requests) e também assíncrona, o que é ideal para pedidos em paralelo. Instala-o com pip:

pip install httpx

Passo 3: Criar uma função assíncrona para uma chamada

Em código assíncrono usamos async def para definir a função e await para esperar pela resposta sem bloquear o resto do programa. Enquanto um pedido espera pela rede, o Python fica livre para tratar dos outros. Esta função vai buscar uma tarefa e devolver o JSON.

async def obter(cliente, id):
    r = await cliente.get(f"https://jsonplaceholder.typicode.com/todos/{id}")
    return r.json()

Repara que a função recebe o cliente como argumento: assim todas as chamadas reutilizam a mesma ligação, o que é mais rápido do que abrir uma nova de cada vez.

Passo 4: Executar várias chamadas em paralelo com asyncio.gather

A função asyncio.gather recebe várias tarefas e executa-as ao mesmo tempo, devolvendo os resultados pela mesma ordem em que os pediste. É o coração das chamadas paralelas.

import asyncio, time, httpx

async def obter(cliente, id):
    r = await cliente.get(f"https://jsonplaceholder.typicode.com/todos/{id}")
    return r.json()

async def principal():
    inicio = time.perf_counter()
    async with httpx.AsyncClient() as cliente:
        tarefas = [obter(cliente, i) for i in range(1, 21)]
        resultados = await asyncio.gather(*tarefas)
    print(f"Paralelo: {time.perf_counter() - inicio:.2f} s")
    return resultados

resultados = asyncio.run(principal())

O *tarefas desdobra a lista como argumentos individuais. Ao correr, o tempo total costuma passar de vários segundos para poucas décimas.

Passo 5: Limitar a concorrência com um Semaphore

Enviar 500 pedidos ao mesmo tempo pode sobrecarregar a API e provocar o erro 429 Too Many Requests. Um Semaphore limita quantas chamadas acontecem em simultâneo, para seres um bom vizinho e evitares bloqueios.

import asyncio, httpx

async def obter(cliente, limite, id):
    async with limite:
        r = await cliente.get(f"https://jsonplaceholder.typicode.com/todos/{id}")
        return r.json()

async def principal():
    limite = asyncio.Semaphore(5)  # no máximo 5 ao mesmo tempo
    async with httpx.AsyncClient(timeout=10) as cliente:
        tarefas = [obter(cliente, limite, i) for i in range(1, 21)]
        return await asyncio.gather(*tarefas)

resultados = asyncio.run(principal())
print(f"Recebidas {len(resultados)} respostas")

Com Semaphore(5), só cinco pedidos correm ao mesmo tempo; os restantes esperam a sua vez de forma automática.

Verificar o resultado

Para confirmar que ficou tudo bem, compara o tempo impresso na versão sequencial (Passo 1) com o da versão paralela (Passo 4): deve ser bastante menor. Confirma também que len(resultados) é igual ao número de pedidos que fizeste (20) e que nenhum resultado vem vazio. Se aparecerem erros de rede, aumenta o timeout ou reduz o valor do Semaphore.

Conclusão

Aprendeste a transformar chamadas lentas, uma a uma, em pedidos paralelos que aproveitam o tempo de espera da rede, e a controlar a carga com um Semaphore. O próximo passo é juntar tratamento de erros — por exemplo, repetir pedidos que falham — e recolher resultados à medida que chegam com asyncio.as_completed. Já pensaste quantos pedidos por segundo a tua API aguenta antes de devolver 429?