Módulo 14 - Performance e profiling
Medir antes de otimizar com timeit
9 min de leitura · por Cesar Gargiulo, revisado pela equipe ValorFinal e GuardiaSec · Atualizado em 01/07/2026
O que você vai aprender
- Entender por que a otimização por palpite quase sempre erra o alvo.
- Usar timeit para medir o tempo de um trecho pequeno de código.
- Comparar duas versões de um código de forma justa, com repetição.
- Reconhecer os erros comuns de medição, como incluir o setup na conta.
Ouvir o resumo desta aula
Um recap de cerca de 2 minutos na voz do Valim, para ouvir no trânsito ou na academia.
Ler a transcrição do resumo
Resumo da aula: Medir antes de otimizar com timeit.
Os objetivos desta aula. Entender por que a otimização por palpite quase sempre erra o alvo. Usar timeit para medir o tempo de um trecho pequeno de código. Comparar duas versões de um código de forma justa, com repetição. Reconhecer os erros comuns de medição, como incluir o setup na conta.
Veja o essencial, parte por parte.
A regra de ouro da performance. Nunca otimize por palpite: meça primeiro, sempre.
Medindo trechos com timeit. Deixe fora da conta o que é só preparação: use o parâmetro setup.
O que o microbenchmark não conta. O timeit é ótimo para trechos pequenos e isolados, mas não conte com ele para entender um programa inteiro.
Esse foi o resumo do essencial. Para se aprofundar, leia a aula completa e responda os exercícios.
A regra de ouro da performance
Existe uma frase antiga entre programadores: a otimização prematura é a raiz de muitos males. Ela não diz para ignorar performance, e sim para não sair mexendo no código na base do achismo. O motivo é simples: a intuição humana sobre o que é lento é péssima. Você jura que aquele laço é o vilão, gasta uma tarde reescrevendo ele, e no fim descobre que o tempo todo estava numa leitura de arquivo que você nem olhou. Por isso a regra de ouro do avançado é medir antes de otimizar. Primeiro você mede e descobre onde o tempo realmente vai; só então decide se e onde vale a pena agir.
Medir também protege você de piorar sem perceber. Sem número na mão, é fácil trocar um código claro por um código torto acreditando que ficou mais rápido, quando na prática nada mudou ou até piorou. Com medição, cada mudança vira uma comparação objetiva: a versão nova é mais rápida que a antiga? Em quanto? Vale a perda de legibilidade? Essa disciplina transforma otimização de adivinhação em engenharia. E a primeira ferramenta dessa disciplina, para trechos pequenos, é o timeit.
Otimização por palpite
- Escolhe o vilão pela intuição
- Reescreve sem número de comparação
- Sacrifica clareza sem prova de ganho
- Muitas vezes mexe fora do gargalo
Otimização com medição
- Descobre o vilão com dados
- Compara a versão nova com a antiga
- Só troca clareza por ganho comprovado
- Age exatamente onde o tempo está
Medindo trechos com timeit
O timeit resolve um problema real de medição: um único cronômetro engana. O relógio do sistema tem baixa resolução, e o sistema operacional pode interromper seu programa no meio da conta. Por isso o timeit roda o mesmo trecho milhares de vezes e reporta o melhor tempo, que é o mais próximo do custo puro do código. No código, você passa a instrução a medir como texto, e um setup separado com o que precisa existir antes, mas que não deve entrar na conta.
import timeit
# Compara juntar strings com + versus str.join numa lista
soma = """
s = ""
for n in range(1000):
s += str(n)
"""
join = """
s = "".join(str(n) for n in range(1000))
"""
t_soma = timeit.timeit(soma, number=1000)
t_join = timeit.timeit(join, number=1000)
print(f"soma com +: {t_soma:.3f}s")
print(f"str.join: {t_join:.3f}s")timeit roda cada trecho 1000 vezes; str.join costuma vencer a concatenação com +.
Repare no cuidado com o que entra na medição. Quando você tem uma preparação que não faz parte do que quer medir, como criar uma lista grande, coloque isso no parâmetro setup, e não junto da instrução. Se o setup entrar na conta, o tempo medido reflete a preparação, não o trecho de interesse, e a comparação fica sem sentido. Esse é o erro mais comum de quem começa a medir: cronometrar o preparo do experimento junto com o experimento.
O que o microbenchmark não conta
O timeit é ótimo para trechos pequenos e isolados, mas não conte com ele para entender um programa inteiro. Medir uma linha fora de contexto pode levar a conclusões falsas: um trecho que parece lento sozinho pode ser irrelevante no todo, porque roda uma vez só, enquanto um trecho aparentemente barato pode ser o vilão por rodar um milhão de vezes. O microbenchmark responde qual das duas versões deste trecho é mais rápida, não onde meu programa gasta tempo. Para essa segunda pergunta, que costuma ser a que importa, existe o profiler, tema da próxima aula.
import timeit
# Medir uma função definida no proprio arquivo:
# passe o setup para importar do escopo global.
def eh_primo(n):
if n < 2:
return False
for d in range(2, int(n ** 0.5) + 1):
if n % d == 0:
return False
return True
t = timeit.timeit("eh_primo(9973)", setup="from __main__ import eh_primo", number=10000)
print(f"eh_primo(9973): {t:.4f}s em 10000 chamadas")Para medir uma função sua, importe-a no setup com from __main__ import.
Guarde a hierarquia mental: primeiro você descobre o gargalo no programa todo, com um profiler; depois, se quiser afinar uma parte específica, usa o timeit para comparar alternativas daquele trecho. Inverter a ordem é o que leva à otimização prematura. Medir a linha errada com precisão de nanossegundo não adianta nada se ela não é o gargalo. A precisão do timeit só rende quando aplicada no lugar que o profiler apontou.
Teste rápido
Por que a regra é medir antes de otimizar?
Perguntas frequentes
- Qual a diferença entre timeit e apenas usar time.time()?
- O time.time() mede uma única execução com o relógio do sistema, que tem baixa resolução e sofre interferência do sistema operacional. O timeit roda o trecho milhares de vezes e reporta o melhor tempo, o que reduz muito o ruído e dá um número confiável para trechos pequenos.
- Por que separar o setup da instrução no timeit?
- Porque o setup é a preparação que não deve entrar na conta, como criar uma lista grande ou importar uma função. Se ele for medido junto, o tempo reflete a preparação e não o trecho que você quer avaliar, e a comparação perde o sentido.
- timeit serve para medir um programa inteiro?
- Não. Ele é feito para trechos pequenos e isolados. Para descobrir onde um programa inteiro gasta tempo, use um profiler como o cProfile, tema da próxima aula. O timeit entra depois, para afinar o trecho específico que o profiler apontou.
- Devo olhar a média ou o melhor tempo das repetições?
- Prefira o melhor tempo. A média é puxada para cima por interrupções do sistema operacional, que não têm relação com a qualidade do seu código. O melhor tempo se aproxima do custo puro do trecho, que é o que você quer comparar.
- Otimizar prematuramente é sempre errado?
- O problema não é pensar em performance, e sim mexer no código por palpite, sacrificando clareza sem prova de ganho. Escrever de forma naturalmente eficiente desde o começo é saudável. Torcer o código antes de medir, na esperança de acelerar, é a otimização prematura que a regra desaconselha.
Fontes
Seu progresso fica salvo neste aparelho. Assinantes sincronizam entre os aparelhos.