Filas de Tarefas em Rust: Guia Prático com Exemplos de Código

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

Introdução: por que filas de tarefas em Rust?

\n\n

No desenvolvimento moderno de sistemas de alta carga, as filas de tarefas (task queues) são um padrão fundamental. Elas permitem separar a geração de tarefas da sua execução, balancear a carga, escalar workers e construir aplicações tolerantes a falhas. Rust, com seu controle rigoroso de memória e ausência de coletor de lixo, oferece capacidades únicas para implementar filas eficientes.

\n\n

Neste artigo, abordaremos três abordagens práticas para trabalhar com filas de tarefas em Rust:

\n
    \n
  • Uso de canais padrão mpsc (multi-produtor, único-consumidor);
  • \n
  • Filas multithread com a biblioteca crossbeam;
  • \n
  • Filas assíncronas com tokio.
  • \n
\n\n

Cada abordagem será acompanhada por um exemplo de código funcional com explicações. Você aprenderá como escolher a ferramenta certa para a tarefa específica e evitar erros comuns.

\n\n

1. Canais clássicos: std::sync::mpsc

\n\n

A biblioteca padrão do Rust fornece o módulo std::sync::mpsc — uma fila multithread com um único consumidor. Esta é a escolha ideal quando você tem vários produtores (threads que enviam tarefas) e um worker (thread que as executa).

\n\n

Exemplo simples: pool de um único worker

\n\n
use std::sync::mpsc;\nuse std::thread;\nuse std::time::Duration;\n\nfn main() {\n    // Criamos um canal: sender (remetente) e receiver (receptor)\n    let (tx, rx) = mpsc::channel::<String>();\n\n    // Iniciamos a thread worker\n    let worker = thread::spawn(move || {\n        for task in rx {\n            println!("[Worker] Executando tarefa: {}", task);\n            thread::sleep(Duration::from_millis(500));\n            println!("[Worker] Tarefa '{}' concluída!", task);\n        }\n    });\n\n    // Criamos vários produtores (em uma única thread para simplificar)\n    let producer = thread::spawn(move || {\n        let tasks = vec![\n            "Processar arquivo A",\n            "Enviar email",\n            "Atualizar banco de dados",\n            "Gerar relatório",\n        ];\n        for task in tasks {\n            println!("[Produtor] Enviando: {}", task);\n            tx.send(task.to_string()).unwrap();\n            thread::sleep(Duration::from_millis(200));\n        }\n    });\n\n    producer.join().unwrap();\n    // Após o sender (tx) ser destruído, o receiver (rx) receberá None e o loop terminará\n    drop(tx); // fechamos o canal do lado do produtor\n    worker.join().unwrap();\n}
\n\n

Características:

\n
    \n
  • O canal mpsc é bufferizado — as tarefas não bloqueiam o remetente até que o buffer esteja cheio.
  • \n
  • Apenas um receptor — esta é uma limitação, mas garante simplicidade e segurança de thread.
  • \n
  • Quando todos os remetentes falham, o canal é fechado automaticamente.
  • \n
\n\n

Vários workers: distribuição manual

\n\n

Se você precisa de vários workers, mpsc não é adequado diretamente. A solução é criar um único canal e várias threads que competirão para receber tarefas. No entanto, isso requer cuidado: Receiver não implementa Sync, então ele precisa ser envolvido em Mutex ou Arc.

\n\n
use std::sync::{mpsc, Arc, Mutex};\nuse std::thread;\nuse std::time::Duration;\n\nfn main() {\n    let (tx, rx) = mpsc::channel::<String>();\n    let rx = Arc::new(Mutex::new(rx));\n\n    let mut workers = vec![];\n    for id in 0..3 {\n        let rx = Arc::clone(&rx);\n        let worker = thread::spawn(move || {\n            loop {\n                let task = {\n                    // Capturamos o mutex e recebemos a tarefa\n                    let rx = rx.lock().unwrap();\n                    rx.recv()\n                };\n                match task {\n                    Ok(task) => {\n                        println!("[Work                

Blogs

Book Recommendations