Rust vs Python: Performance e Quando Usar | Rust Brasil

Rust vs Python: performance, tipagem, FFI com PyO3 e quando migrar. Comparação detalhada com benchmarks e exemplos práticos.

Introdução

Python e Rust ocupam extremos opostos do espectro de linguagens de programação. Python é a linguagem mais popular do mundo em 2026, dominando áreas como ciência de dados, machine learning, automação e desenvolvimento web rápido. Rust é uma linguagem de sistemas focada em performance e segurança, cada vez mais usada para reescrever componentes críticos que antes seriam feitos em C ou C++.

A pergunta não é realmente “qual é melhor?” — cada uma brilha em contextos completamente diferentes. Este artigo vai ajudá-lo a entender quando faz sentido usar Python, quando usar Rust e, mais importante, como combinar as duas com ferramentas como PyO3.

Se você é um desenvolvedor Python curioso sobre Rust, ou um rustacean querendo entender o ecossistema Python, este guia é para você.

Tabela Comparativa

AspectoRustPython
ParadigmaMulti-paradigma (funcional, imperativo)Multi-paradigma (OOP, funcional, imperativo)
TipagemEstática, forte, em tempo de compilaçãoDinâmica, forte (duck typing)
PerformancePróxima de C (compilada, LLVM)10-100x mais lenta (interpretada, GIL)
Gerenciamento de memóriaOwnership + Borrow CheckerGarbage Collector + Reference Counting
ConcorrênciaThreads reais + async/awaitGIL limita threads; asyncio para I/O
Curva de aprendizadoÍngreme (ownership, lifetimes, tipos)Muito suave (pseudocódigo executável)
Ecossistemacrates.io (~150k crates)PyPI (~500k pacotes)
Uso principalSistemas, CLI, WebAssembly, infraestruturaData science, ML, web, automação, scripts
REPLNão oficial (evcxr)Excelente (IPython, Jupyter)
Tempo de desenvolvimentoMais lento (compilação + tipos)Muito rápido (prototipagem ágil)

Exemplos de Código: Processamento de Dados

Vamos comparar uma tarefa comum: ler um arquivo CSV, filtrar registros e calcular uma média.

Python

import csv
from statistics import mean

def processar_vendas(caminho: str) -> dict:
    """Lê CSV de vendas e retorna estatísticas por região."""
    vendas_por_regiao: dict[str, list[float]] = {}

    with open(caminho, "r", encoding="utf-8") as arquivo:
        leitor = csv.DictReader(arquivo)
        for linha in leitor:
            regiao = linha["regiao"]
            valor = float(linha["valor"])
            if valor > 0:
                vendas_por_regiao.setdefault(regiao, []).append(valor)

    return {
        regiao: {
            "total": sum(valores),
            "media": mean(valores),
            "quantidade": len(valores),
        }
        for regiao, valores in vendas_por_regiao.items()
    }

resultado = processar_vendas("vendas.csv")
for regiao, stats in resultado.items():
    print(f"{regiao}: total={stats['total']:.2f}, média={stats['media']:.2f}")

Rust

use std::collections::HashMap;
use std::error::Error;
use std::fs::File;

#[derive(Debug)]
struct Estatisticas {
    total: f64,
    media: f64,
    quantidade: usize,
}

fn processar_vendas(caminho: &str) -> Result<HashMap<String, Estatisticas>, Box<dyn Error>> {
    let arquivo = File::open(caminho)?;
    let mut leitor = csv::Reader::from_reader(arquivo);
    let mut vendas_por_regiao: HashMap<String, Vec<f64>> = HashMap::new();

    for resultado in leitor.records() {
        let registro = resultado?;
        let regiao = registro[1].to_string(); // coluna "regiao"
        let valor: f64 = registro[2].parse()?; // coluna "valor"
        if valor > 0.0 {
            vendas_por_regiao.entry(regiao).or_default().push(valor);
        }
    }

    let estatisticas = vendas_por_regiao
        .into_iter()
        .map(|(regiao, valores)| {
            let total: f64 = valores.iter().sum();
            let quantidade = valores.len();
            let media = total / quantidade as f64;
            (regiao, Estatisticas { total, media, quantidade })
        })
        .collect();

    Ok(estatisticas)
}

fn main() -> Result<(), Box<dyn Error>> {
    let resultado = processar_vendas("vendas.csv")?;
    for (regiao, stats) in &resultado {
        println!("{}: total={:.2}, média={:.2}", regiao, stats.total, stats.media);
    }
    Ok(())
}

O código Python é mais conciso e legível. O código Rust é mais verboso, mas trata erros explicitamente com Result, não tem overhead de GC e processa o arquivo significativamente mais rápido — especialmente para arquivos grandes.

Para mais exemplos de processamento de dados em Rust, veja nossa receita de parse JSON.

A Diferença de Performance: Por Que 100x?

A diferença de velocidade entre Rust e Python em operações CPU-bound pode chegar a 100x ou mais. Vamos entender o porquê:

Benchmark: Fibonacci Recursivo

# Python
def fib(n: int) -> int:
    if n <= 1:
        return n
    return fib(n - 1) + fib(n - 2)

# fib(40) em Python: ~25 segundos
// Rust
fn fib(n: u64) -> u64 {
    if n <= 1 {
        return n;
    }
    fib(n - 1) + fib(n - 2)
}

// fib(40) em Rust: ~0.25 segundos

Por Que Essa Diferença Existe?

FatorPythonRust
InterpretaçãoBytecode interpretado pelo CPythonCompilado para código de máquina nativo
Tipagem dinâmicaVerificação de tipo em runtime a cada operaçãoTipos resolvidos em tempo de compilação
Boxed integersCada int é um objeto no heapInteiros ficam em registradores da CPU
GILImpede paralelismo real em threadsThreads reais com paralelismo total
Cache de CPULayouts de memória dispersosDados contíguos, cache-friendly

Benchmarks Realistas

TarefaPythonRustSpeedup
Parse de JSON (1GB)45s0,8s~56x
Ordenação (10M números)12s0,4s~30x
Regex em arquivo (500MB)18s0,3s~60x
Servidor HTTP (req/s)~15.000 (uvicorn)~850.000 (axum)~57x
Fibonacci(40)25s0,25s~100x

Ponte Entre Mundos: PyO3

A melhor parte é que você não precisa escolher. O PyO3 permite escrever extensões Python em Rust, combinando a produtividade do Python com a performance do Rust:

// lib.rs — extensão Python escrita em Rust
use pyo3::prelude::*;

#[pyfunction]
fn soma_rapida(numeros: Vec<f64>) -> f64 {
    numeros.iter().sum()
}

#[pyfunction]
fn filtrar_positivos(numeros: Vec<f64>) -> Vec<f64> {
    numeros.into_iter().filter(|&n| n > 0.0).collect()
}

#[pymodule]
fn meu_modulo_rust(m: &Bound<'_, PyModule>) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(soma_rapida, m)?)?;
    m.add_function(wrap_pyfunction!(filtrar_positivos, m)?)?;
    Ok(())
}
# Usando a extensão Rust em Python
import meu_modulo_rust

numeros = [1.5, -2.0, 3.7, -0.5, 8.1]

total = meu_modulo_rust.soma_rapida(numeros)
print(f"Soma: {total}")  # Soma: 10.8

positivos = meu_modulo_rust.filtrar_positivos(numeros)
print(f"Positivos: {positivos}")  # Positivos: [1.5, 3.7, 8.1]

Projetos como Polars (alternativa ao Pandas, 10-100x mais rápido), Pydantic v2 (validação de dados), ruff (linter Python mais rápido do mundo) e uv (gerenciador de pacotes) já usam essa abordagem com sucesso.

Tipagem: Dinâmica vs Estática na Prática

A diferença de tipagem entre Python e Rust vai além de performance. Ela afeta diretamente a experiência de manutenção e refatoração de código.

Python: Type Hints São Opcionais

# Python: type hints não são enforçados em runtime
def calcular_desconto(preco: float, percentual: float) -> float:
    return preco * (1 - percentual / 100)

# Isso funciona em runtime, apesar de estar "errado" tipadamente
resultado = calcular_desconto("100", "10")  # String, não float!
# TypeError em runtime, não em "compilação"

Python adicionou type hints (PEP 484), e ferramentas como mypy e pyright fazem verificação estática, mas são opcionais. Muitas bibliotecas e projetos legados não têm types, e o ecossistema ainda está em transição.

Rust: Tipos São Obrigatórios e Verificados

fn calcular_desconto(preco: f64, percentual: f64) -> f64 {
    preco * (1.0 - percentual / 100.0)
}

fn main() {
    let resultado = calcular_desconto(100.0, 10.0);
    println!("Preço com desconto: R${resultado:.2}");

    // calcular_desconto("100", "10"); // ERRO DE COMPILAÇÃO: tipos incompatíveis
}

Em Rust, o sistema de tipos é obrigatório e verificado em compilação. Isso significa que refatorações em projetos grandes são muito mais seguras — se compila, os tipos estão corretos.

Ferramentas Python Escritas em Rust

Um fenômeno interessante em 2026 é que muitas das ferramentas mais populares do ecossistema Python são escritas em Rust:

  • ruff: linter e formatter 10-100x mais rápido que flake8/black
  • uv: gerenciador de pacotes Python 10-100x mais rápido que pip
  • Polars: biblioteca de DataFrames alternativa ao Pandas, 10-50x mais rápida
  • Pydantic v2: core de validação reescrito em Rust, 5-50x mais rápido
  • tokenizers (Hugging Face): tokenização de texto para NLP
  • cryptography: backend criptográfico seguro

Isso demonstra o padrão que se consolida: Python como interface, Rust como motor de performance.

Quando Usar Python

Escolha Python quando:

  • Prototipagem rápida: validar ideias em horas, não dias
  • Data Science e Machine Learning: NumPy, Pandas, scikit-learn, PyTorch, TensorFlow
  • Automação e scripts: tarefas administrativas, ETL, web scraping
  • APIs simples: FastAPI/Django para CRUDs e MVPs
  • A equipe é de cientistas de dados: Python é a lingua franca da área
  • Jupyter Notebooks: exploração interativa de dados

Quando Usar Rust

Escolha Rust quando:

  • Performance é crítica: processamento de dados em larga escala, sistemas de baixa latência
  • O gargalo do Python é a CPU: loops intensivos, cálculos numéricos sem NumPy
  • Confiabilidade importa: sistemas que não podem crashar, infraestrutura crítica
  • Consumo de memória importa: serverless, containers, dispositivos embarcados
  • Você precisa de concorrência real: processamento paralelo sem o GIL
  • CLIs de alta performance: ferramentas como ripgrep, fd, bat

Quando Combinar os Dois

A abordagem mais inteligente em muitos cenários é usar Python como cola e Rust nos pontos quentes:

  1. Escreva a lógica de negócios e orquestração em Python
  2. Profile o código para encontrar gargalos
  3. Reescreva apenas os gargalos em Rust usando PyO3
  4. Mantenha a interface Python para o resto da equipe

Essa estratégia é usada por empresas como Dropbox, Discord e Cloudflare.

Conclusão e Recomendação

Para a maioria dos desenvolvedores Python, a recomendação é: continue usando Python como sua linguagem principal, mas aprenda Rust para estender Python quando a performance não for suficiente. A combinação Python + Rust via PyO3 oferece o melhor dos dois mundos.

Se você está começando um projeto novo que é principalmente CPU-bound (compilador, game engine, sistema embarcado, processamento de dados em escala), comece em Rust. O investimento inicial na curva de aprendizado se paga com manutenção mais simples e performance superior.

Não reescreva projetos Python inteiros em Rust a menos que tenha uma razão muito forte. Identifique os 10% do código que causam 90% dos problemas de performance e reescreva apenas esses trechos.

Para começar com Rust vindo do Python, recomendamos nosso tutorial de primeiros passos.


Veja Também