Concorrência e Multithreading em Rust: Segurança e Desempenho

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: escrevendo código seguro e rápido



Programas modernos raramente funcionam em modo single-thread. Processamento de requisições, trabalho com arquivos, operações de rede — tudo isso exige execução paralela de tarefas. Rust oferece uma abordagem única para concorrência: ele garante segurança de memória em tempo de compilação, prevenindo data races. Neste artigo, vamos explorar como trabalhar com threads, canais, mutexes e assincronia em Rust.



1. Fundamentos de multithreading: criação e gerenciamento de threads



Em Rust, as threads são criadas através da biblioteca padrão std::thread. Cada thread executa independentemente, mas o compilador monitora rigorosamente o tempo de vida das variáveis.



Criando uma thread

use std::thread;use std::time::Duration;

fn main() { let handle = thread::spawn(|| { for i in 1..10 { println!("Thread: {}", i); thread::sleep(Duration::from_millis(100)); } });

for i in 1..5 { println!("Thread principal: {}", i); thread::sleep(Duration::from_millis(100)); }

handle.join().unwrap(); // Aguarda a conclusão da thread}


Captura de ownership em closures

Se uma thread usa variáveis do escopo externo, é necessário transferir a ownership com move:

let data = vec![1, 2, 3];

let handle = thread::spawn(move || { println!("Dados: {:?}", data);});

handle.join().unwrap();// println!("{:?}", data); // Erro! data foi movida


2. Compartilhamento de dados: mutexes e locks



Para acesso seguro a dados compartilhados entre múltiplas threads, Rust usa Mutex (mutex) em conjunto com Arc (contador atômico de referências).



Exemplo com Mutex e Arc

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!("Resultado: {}", *counter.lock().unwrap()); // 10}


Importante: Mutex é desbloqueado automaticamente ao sair do escopo. Isso previne deadlocks em nível de compilação.



RwLock — para leitura frequente

Se os dados raramente são modificados, mas frequentemente lidos, use RwLock:

use std::sync::RwLock;

let lock = RwLock::new(5);

{ let r1 = lock.read().unwrap(); let r2 = lock.read().unwrap(); // Pode ler simultaneamente println!("{} {}", r1, r2);}

{ let mut w = lock.write().unwrap(); *w += 1; // Escrita bloqueia leitura}


3. Canais: passagem de mensagens entre threads



Rust suporta o modelo de atores através de canais (std::sync::mpsc). Isso permite que threads troquem dados sem memória compartilhada.



Exemplo com canal

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

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

thread::spawn(move || { let vals = vec![\"hello\", \"from\", \"the\", \"thread\"]; for val in vals { tx.send(val).unwrap(); thread::sleep(std::time::Duration::from_secs(1)); } });

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


Múltiplos remetentes

Com mpsc::Sender, é possível clonar o remetente para várias threads:

let (tx, rx) = mpsc::channel();let tx1 = tx.clone();

thread::spawn(move || { tx1.send(\"Thread 1\").unwrap(); });thread::spawn(move || { tx.send(\"

Blogs

Book Recommendations