NumPy: Otimização de Desempenho
Última atualização: 2026-08-26
1. O que Você Aprenderá
- ❶ Vetorização — a regra #1 de desempenho
- ❷ Layout de memória: C-contíguo vs Fortran-contíguo
- ❸ Operações in-place vs cópias
- ❹ Profilando código NumPy
- ❺ Armadilhas comuns de desempenho
2. Conceitos-Chave
(1) Vetorização
import numpy as np
import time
n = 10_000_000
a = np.random.rand(n)
b = np.random.rand(n)
# Lento: loop Python
t0 = time.time()
c = np.empty(n)
for i in range(n):
c[i] = a[i] + b[i]
t1 = time.time()
# Rápido: vetorizado
t2 = time.time()
d = a + b
t3 = time.time()
print(f"Loop: {t1-t0:.3f}s, Vetorizado: {t3-t2:.6f}s")
print(f"Aceleração: {(t1-t0)/(t3-t2):.0f}x")
(2) Operações In-Place
# Evite cópias com o parâmetro out=
a = np.random.rand(1000000)
b = np.random.rand(1000000)
# Cópia (aloca nova memória)
c = a + b
# In-place (sem alocação)
np.add(a, b, out=a)
▶ Exemplo: Comparação de velocidade da vetorização (Dificuldade ⭐⭐)
import numpy as np
import time
n = 1_000_000
a = np.random.rand(n)
b = np.random.rand(n)
# Lento: loop Python
t0 = time.time()
c = np.empty(n)
for i in range(n):
c[i] = a[i] + b[i]
t1 = time.time()
# Rápido: vetorizado
t2 = time.time()
d = a + b
t3 = time.time()
loop_time = t1 - t0
vec_time = t3 - t2
print(f"Loop: {loop_time:.3f}s, Vetorizado: {vec_time:.6f}s")
print(f"Aceleração: {loop_time/vec_time:.0f}x")
Output:
TEXT 📖 Somente leituraLoop: 0.312s, Vetorizado: 0.002s Aceleração: 156x
▶ Exemplo: Operações in-place com out= (Dificuldade ⭐⭐)
import numpy as np
a = np.array([10, 20, 30, 40, 50])
b = np.array([1, 2, 3, 4, 5])
# Sem out: cria novo array
c = np.add(a, b)
print("Sem out:", c)
# Com out: reutiliza memória existente
result = np.empty(5)
np.add(a, b, out=result)
print("Com out:", result)
# Encadear operações in-place
np.multiply(result, 2, out=result)
np.add(result, 1, out=result)
print("Encadeado:", result)
Output:
TEXT 📖 Somente leituraSem out: [11 22 33 44 55] Com out: [11 22 33 44 55] Encadeado: [23 45 67 89 111]
▶ Exemplo: Impacto do layout de memória (Dificuldade ⭐)
import numpy as np
# C-contíguo (linha-majoritária) — padrão
c = np.array([[1, 2, 3], [4, 5, 6]])
print("C-contíguo:", c.flags.c_contiguous)
print("Fortran-contíguo:", c.flags.f_contiguous)
# Converter para Fortran-contíguo (coluna-majoritária)
f = np.asfortranarray(c)
print("Fortran-contíguo:", f.flags.f_contiguous)
# Shape e strides
print("C strides:", c.strides)
print("F strides:", f.strides)
Output:
TEXT 📖 Somente leituraC-contíguo: True Fortran-contíguo: False Fortran-contíguo: True C strides: (24, 8) F strides: (8, 24)
❓ Perguntas Frequentes
P: Qual é a única regra de desempenho mais importante? R: Evite loops Python. Toda vez que você escreve
for i in range(n), pergunte: "Posso vetorizar isso?" Se sim, o NumPy será 10-100x mais rápido.
P: Qual é a diferença entre ordem C e ordem Fortran? R: Ordem C (linha-majoritária) armazena linhas contiguamente. Ordem Fortran (coluna-majoritária) armazena colunas contiguamente. Use a ordem que corresponde ao seu padrão de acesso para melhor desempenho de cache.
P: Quando devo usar o parâmetro
out=? R: Quando você está fazendo muitas operações no mesmo array grande,out=evita alocar nova memória para cada operação. Use-o em loops e pipelines.
📖 Resumo
- Vetorização é a regra #1 de desempenho — evite loops Python a todo custo
- Use o parâmetro
out=para operações in-place e evitar alocações - C-contíguo (linha-majoritária) é o padrão; corresponda o padrão de acesso ao layout de memória
- Profile com
%timeitno Jupyter outime.perf_counter()em scripts - Armadilhas comuns: loops, cópias desnecessárias, memória não contígua após transpose
📝 Exercícios
-
Básico (Dificuldade ⭐): Compare o tempo para computar
a + bpara 10 milhões de elementos usando um loop vs vetorização. Registre o fator de aceleração. -
Intermediário (Dificuldade ⭐⭐): Compare o tempo de
a + bcom e semout=a. Meça a diferença na sobrecarga de alocação. -
Desafio (Dificuldade ⭐⭐⭐): Crie um array grande, transponha-o e depois some ao longo de um eixo. Compare o desempenho do array transposto vs uma cópia contígua. Explique a diferença.