Concorrência e Multithreading em Rust: Técnicas Avançadas

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Concorrência e Multithreading em Rust: dos Fundamentos às Técnicas Avançadas



Rust conquistou a reputação de uma das linguagens de programação de sistemas mais seguras, em grande parte devido ao seu modelo de propriedade (ownership) e sistema de tipos que previne condições de corrida em tempo de compilação. No entanto, concorrência não é apenas segurança, mas também eficiência. Neste artigo, exploraremos aspectos avançados do trabalho com concorrência e multithreading em Rust: desde primitivas básicas de sincronização até runtimes assíncronos modernos. O material é voltado para desenvolvedores que já conhecem os fundamentos da linguagem.



1. Multithreading Seguro: Send, Sync e Arc<Mutex<T>>



A base do multithreading seguro em Rust são duas traits-chave: Send e Sync. Um tipo que implementa Send pode ser transferido com segurança entre threads. Um tipo que implementa Sync pode ser compartilhado com segurança entre threads por referência. A maioria dos tipos padrão (por exemplo, i32, String) implementa ambas as traits automaticamente, se contiverem apenas dados Send/Sync.



Para acesso compartilhado a dados mutáveis de várias threads, o padrão Arc<Mutex<T>> é frequentemente usado. Arc (contagem de referência atômica) permite compartilhar a propriedade entre threads, enquanto Mutex garante exclusão mútua.



use std::sync::{Arc, Mutex};use std::thread;

fn main() { let counter = Arc::new(Mutex::new(0)); let mut handles = vec![];

for _ in 0..10 { let counter = Arc::clone(&counter); let handle = thread::spawn(move || { let mut num = counter.lock().unwrap(); *num += 1; }); handles.push(handle); }

for handle in handles { handle.join().unwrap(); }

println!("Result: {}", *counter.lock().unwrap());}


É importante lembrar: Mutex em Rust não é apenas um bloqueio, mas um contêiner que protege os dados. A aquisição do bloqueio retorna um ponteiro inteligente MutexGuard, que libera automaticamente o bloqueio ao sair do escopo. Isso elimina o erro clássico de "esqueci de destravar".



Dica Avançada: RwLock em vez de Mutex



Se seus dados são frequentemente lidos, mas raramente modificados, use RwLock. Ele permite que múltiplas threads leiam os dados simultaneamente, mas bloqueia a escrita enquanto houver pelo menos um leitor. Isso pode aumentar significativamente o desempenho em cenários de "mais leitores do que escritores".



use std::sync::RwLock;

let data = RwLock::new(vec![1, 2, 3]);

// Leitura — múltiplas threads podem ler simultaneamentelet read_guard = data.read().unwrap();println!("Primeiro elemento: {}", read_guard[0]);drop(read_guard); // Libera o bloqueio explicitamente

// Escrita — acesso exclusivolet mut write_guard = data.write().unwrap();write_guard.push(4);


2. Canais (Channels): Transmissão de Mensagens entre Threads



Canais são uma alternativa à memória compartilhada. Em Rust, existem dois tipos principais de canais: std::sync::mpsc (Multi-Produtor, Único-Consumidor) e crossbeam-channel (Multi-Produtor, Multi-Consumidor).



O mpsc padrão é ideal para cenários de "um consumidor — muitos produtores". Ele funciona como uma fila: os remetentes colocam mensagens, o destinatário as retira na ordem FIFO.



use std::sync::mpsc;use std::thread;

fn main() { let (tx, rx) = mpsc::channel();

let tx1 = tx.clone(); thread::spawn(move || { tx1.send("Mensagem da thread 1").unwrap(); });

thread::spawn(move || { tx.send("Mensagem da thread 2").unwrap(); });

for received in rx { println!("Recebido: {}", received); }}


Blogs

Book Recommendations