---
title: "Rayon em Rust: Paralelismo de Dados sem Medo"
url: "https://rustlang.com.br/blog/rayon-paralelismo-dados-rust/"
markdown_url: "https://rustlang.com.br/blog/rayon-paralelismo-dados-rust.MD"
description: "Guia completo sobre Rayon em Rust: aprenda paralelismo de dados com par_iter, work stealing, benchmarks e exemplos práticos para acelerar seu código."
date: "2026-03-27"
author: "Equipe Rust Brasil"
---

# Rayon em Rust: Paralelismo de Dados sem Medo

Guia completo sobre Rayon em Rust: aprenda paralelismo de dados com par_iter, work stealing, benchmarks e exemplos práticos para acelerar seu código.


## Introdução

Paralelismo em Rust não precisa ser complicado. Enquanto muitas linguagens exigem gerenciamento manual de threads, locks e sincronização, o [Rayon](/ecossistema/rayon/) oferece uma abordagem radicalmente simples: troque `.iter()` por `.par_iter()` e seu código roda em paralelo — com toda a segurança que o Rust garante em tempo de compilação.

Rayon é uma biblioteca de **paralelismo de dados** que transforma operações sequenciais em paralelas de forma quase transparente. Com mais de 150 milhões de downloads no crates.io e presente em projetos como ripgrep, cargo e rustfmt, é uma das crates mais confiáveis do [ecossistema Rust](/blog/ecossistema-rust-2026/).

Neste guia, vamos explorar desde os fundamentos até padrões avançados, com benchmarks reais e exemplos práticos.

## Paralelismo de Dados vs Paralelismo de Tarefas

Antes de mergulhar no Rayon, é importante entender a diferença entre os dois modelos de paralelismo:

- **Paralelismo de dados**: A mesma operação é aplicada simultaneamente a diferentes partes de um conjunto de dados. Exemplo: processar cada pixel de uma imagem ao mesmo tempo.
- **Paralelismo de tarefas**: Diferentes operações são executadas simultaneamente. Exemplo: um servidor web processando múltiplas requisições.

Rayon se especializa no primeiro modelo. Para paralelismo de tarefas e I/O assíncrono, [Tokio](/ecossistema/tokio/) é a escolha certa — veja nosso artigo sobre o [ecossistema async em 2026](/blog/async-rust-ecossistema-2026/).

## Primeiros Passos com Rayon

Adicione Rayon ao seu `Cargo.toml`:

```toml
[dependencies]
rayon = "1.10"
```

### O Básico: par_iter()

```rust
use rayon::prelude::*;

fn main() {
    let numeros: Vec<u64> = (1..=10_000_000).collect();

    // Sequencial
    let soma_seq: u64 = numeros.iter()
        .map(|&n| n * n)
        .sum();

    // Paralelo — apenas troque iter() por par_iter()
    let soma_par: u64 = numeros.par_iter()
        .map(|&n| n * n)
        .sum();

    assert_eq!(soma_seq, soma_par);
    println!("Soma dos quadrados: {}", soma_par);
}
```

É isso. Uma mudança de quatro letras (`par_`) e seu código agora utiliza todos os cores disponíveis da CPU.

### Operações Paralelas Disponíveis

Rayon implementa versões paralelas de todos os adaptadores de [iteradores do Rust](/artigos/iteradores-rust/):

```rust
use rayon::prelude::*;

fn main() {
    let dados: Vec<i64> = (-500_000..500_000).collect();

    // map paralelo
    let quadrados: Vec<i64> = dados.par_iter()
        .map(|&x| x * x)
        .collect();

    // filter paralelo
    let positivos: Vec<&i64> = dados.par_iter()
        .filter(|&&x| x > 0)
        .collect();

    // for_each paralelo (efeitos colaterais)
    dados.par_iter()
        .filter(|&&x| x % 100_000 == 0)
        .for_each(|x| println!("Múltiplo encontrado: {}", x));

    // reduce paralelo
    let maximo = dados.par_iter()
        .reduce(|| &i64::MIN, |a, b| if a > b { a } else { b });

    // find_any — retorna QUALQUER match (não necessariamente o primeiro)
    let encontrado = dados.par_iter()
        .find_any(|&&x| x == 42);

    println!("Quadrados: {}, Positivos: {}", quadrados.len(), positivos.len());
    println!("Máximo: {}, Encontrado 42: {:?}", maximo, encontrado);
}
```

## Como o Work Stealing Funciona

Rayon utiliza um **work-stealing scheduler** para distribuir trabalho entre threads de forma eficiente:

1. O trabalho é dividido recursivamente em pedaços menores (fork)
2. Cada thread tem sua própria fila de tarefas
3. Quando uma thread termina suas tarefas, ela "rouba" trabalho da fila de outra thread
4. Resultado final é combinado (join)

Esse modelo garante balanceamento de carga automático, mesmo quando as tarefas têm custos variados. Não é necessário particionar manualmente os dados — o Rayon faz isso de forma adaptativa.

## Benchmarking: Serial vs Paralelo

Vamos medir a diferença real usando [Criterion](/ecossistema/criterion/):

```toml
[dev-dependencies]
criterion = { version = "0.5", features = ["html_reports"] }
rayon = "1.10"

[[bench]]
name = "paralelo"
harness = false
```

```rust
// benches/paralelo.rs
use criterion::{criterion_group, criterion_main, Criterion, black_box};
use rayon::prelude::*;

fn processar_sequencial(dados: &[f64]) -> Vec<f64> {
    dados.iter()
        .map(|x| (x.sin() * x.cos()).sqrt().abs())
        .collect()
}

fn processar_paralelo(dados: &[f64]) -> Vec<f64> {
    dados.par_iter()
        .map(|x| (x.sin() * x.cos()).sqrt().abs())
        .collect()
}

fn benchmark(c: &mut Criterion) {
    let dados: Vec<f64> = (0..5_000_000)
        .map(|i| i as f64 * 0.001)
        .collect();

    let mut group = c.benchmark_group("processamento");

    group.bench_function("sequencial", |b| {
        b.iter(|| processar_sequencial(black_box(&dados)))
    });

    group.bench_function("paralelo", |b| {
        b.iter(|| processar_paralelo(black_box(&dados)))
    });

    group.finish();
}

criterion_group!(benches, benchmark);
criterion_main!(benches);
```

Resultados típicos em uma máquina com 8 cores:

| Operação | Tempo (5M elementos) | Speedup |
|----------|----------------------|---------|
| Sequencial | ~120ms | 1x |
| Paralelo (Rayon) | ~18ms | ~6.7x |

O speedup não é exatamente 8x por causa do overhead de coordenação e da contenção de memória, mas está próximo do ideal teórico.

## Ordenação Paralela

Rayon oferece versões paralelas de algoritmos de ordenação:

```rust
use rayon::prelude::*;

fn main() {
    let mut dados: Vec<u64> = (0..10_000_000)
        .map(|_| rand::random::<u64>())
        .collect();

    // Ordenação paralela estável
    dados.par_sort();

    // Ordenação paralela instável (mais rápida)
    dados.par_sort_unstable();

    // Ordenação paralela com comparador personalizado
    dados.par_sort_unstable_by(|a, b| b.cmp(a)); // Decrescente

    println!("Primeiros 5: {:?}", &dados[..5]);
}
```

Para conjuntos grandes (>100K elementos), `par_sort_unstable()` pode ser 3-4x mais rápido que `sort_unstable()`.

## Controlando o Thread Pool

Por padrão, Rayon cria uma thread por core lógico. Você pode personalizar isso:

```rust
use rayon::ThreadPoolBuilder;

fn main() {
    // Thread pool global com 4 threads
    ThreadPoolBuilder::new()
        .num_threads(4)
        .build_global()
        .unwrap();

    // Ou criar pools isolados para diferentes cargas de trabalho
    let pool_pesado = ThreadPoolBuilder::new()
        .num_threads(6)
        .thread_name(|i| format!("pesado-{}", i))
        .build()
        .unwrap();

    let resultado = pool_pesado.install(|| {
        let dados: Vec<u64> = (1..=1_000_000).collect();
        dados.par_iter().map(|&n| n * n).sum::<u64>()
    });

    println!("Resultado: {}", resultado);
}
```

## Exemplos Práticos do Mundo Real

### Processamento de Imagens

```rust
use rayon::prelude::*;

struct Pixel {
    r: u8, g: u8, b: u8,
}

impl Pixel {
    fn escala_cinza(&self) -> u8 {
        ((self.r as f32 * 0.299) +
         (self.g as f32 * 0.587) +
         (self.b as f32 * 0.114)) as u8
    }
}

fn converter_escala_cinza(pixels: &[Pixel]) -> Vec<u8> {
    pixels.par_iter()
        .map(|p| p.escala_cinza())
        .collect()
}
```

### Processamento de Arquivos em Lote

```rust
use rayon::prelude::*;
use std::fs;
use std::path::PathBuf;

fn processar_arquivos(caminhos: &[PathBuf]) -> Vec<(PathBuf, usize)> {
    caminhos.par_iter()
        .filter_map(|caminho| {
            let conteudo = fs::read_to_string(caminho).ok()?;
            let contagem = conteudo.lines().count();
            Some((caminho.clone(), contagem))
        })
        .collect()
}
```

### Análise de Dados com Agregação

```rust
use rayon::prelude::*;

#[derive(Debug)]
struct Venda {
    produto: String,
    valor: f64,
    quantidade: u32,
}

fn calcular_estatisticas(vendas: &[Venda]) -> (f64, f64, f64) {
    let total: f64 = vendas.par_iter()
        .map(|v| v.valor * v.quantidade as f64)
        .sum();

    let media = total / vendas.len() as f64;

    let max = vendas.par_iter()
        .map(|v| v.valor)
        .reduce(|| f64::MIN, f64::max);

    (total, media, max)
}
```

## Rayon vs std::thread vs Tokio

Escolher a ferramenta certa depende do tipo de trabalho:

| Cenário | Melhor escolha | Por quê |
|---------|---------------|---------|
| Processar coleção grande | **Rayon** | Paralelismo de dados automático |
| Poucas threads com lógica complexa | **std::thread** | Controle total |
| I/O assíncrono (HTTP, DB) | **Tokio** | Non-blocking I/O |
| Servidor web com muitas conexões | **Tokio** | Escalabilidade de I/O |
| Pipeline de dados CPU-bound | **Rayon** | Work stealing eficiente |
| Background jobs simples | **std::thread** | Sem dependências extras |

Para uma comparação mais ampla de concorrência, veja nosso [tutorial sobre concorrência em Rust](/tutoriais/concorrencia/). E se sua carga é I/O-bound, confira o [guia do Tokio](/ecossistema/tokio/).

## Quando NÃO Usar Rayon

Rayon não é bala de prata. Evite em:

1. **Workloads pequenos**: Para vetores com menos de ~10.000 elementos, o overhead de coordenação pode tornar o código paralelo mais lento que o sequencial.

2. **I/O-bound**: Rayon é otimizado para CPU-bound. Para operações de I/O (requisições HTTP, leitura de disco), use [async/await](/blog/async-rust-ecossistema-2026/).

3. **Estado compartilhado com muita contenção**: Se cada iteração precisa acessar um Mutex, o lock contention pode eliminar qualquer ganho.

4. **Ordem garantida**: `par_iter()` não garante ordem de processamento. Se a ordem importa, use `par_bridge()` com cuidado ou mantenha o iterador sequencial.

## Paralelismo Aninhado

Rayon lida naturalmente com paralelismo aninhado — chamadas paralelas dentro de chamadas paralelas:

```rust
use rayon::prelude::*;

fn main() {
    let matrizes: Vec<Vec<Vec<f64>>> = (0..10)
        .map(|_| {
            (0..1000).map(|_| {
                (0..1000).map(|i| i as f64).collect()
            }).collect()
        })
        .collect();

    // Paralelismo em dois níveis
    let resultados: Vec<Vec<f64>> = matrizes.par_iter()
        .map(|matriz| {
            matriz.par_iter()
                .map(|linha| linha.iter().sum::<f64>())
                .collect()
        })
        .collect();

    println!("Processadas {} matrizes", resultados.len());
}
```

O scheduler do Rayon automaticamente distribui o trabalho de forma eficiente entre os níveis de paralelismo, sem criar threads excessivas.

## Conclusão

Rayon demonstra a filosofia do Rust de oferecer abstrações de custo zero — ou quase zero — que tornam código paralelo tão seguro quanto código sequencial. Com a garantia do compilador contra data races e a ergonomia do `par_iter()`, não há desculpa para deixar cores ociosos.

Se você está começando com Rust, confira [Como Aprender Rust em 2026](/blog/como-aprender-rust-2026/). Para quem quer dominar o sistema de tipos que torna tudo isso possível, veja nosso tutorial sobre [Traits e Generics](/tutoriais/traits-generics/).

Para entender como a compilação condicional pode otimizar seu código paralelo para diferentes plataformas, leia nosso artigo sobre [Compilação Condicional em Rust](/blog/compilacao-condicional-rust-cfg-features/).

### Veja Também

- [Closures em Rust](/artigos/closures-rust/)
- [Otimização de Performance](/artigos/otimizacao-performance/)
- [Smart Pointers](/artigos/smart-pointers/)
- [Top Projetos Open Source Rust 2026](/blog/top-projetos-open-source-rust-2026/)

Outras linguagens também oferecem ferramentas para paralelismo: <a href="https://golang.com.br/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'golang.com.br' })">Go tem goroutines</a> com modelo CSP, <a href="https://ziglang.com.br/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'ziglang.com.br' })">Zig oferece controle manual de threads</a> com async/await integrado, e <a href="https://python.dev.br/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'python.dev.br' })">Python usa multiprocessing</a> para contornar o GIL.
