Introdução à programação assíncrona em Rust
Programação assíncrona é um paradigma que permite executar operações de entrada/saída (requisições de rede, leitura de arquivos, trabalho com bancos de dados) sem bloquear o fluxo principal de execução. Em Rust, a assincronia é implementada através do sistema Future e das palavras-chave async/await. Diferente de multithreading, o código assíncrono executa em uma única thread, alternando entre tarefas durante períodos de espera.
Neste guia, abordaremos:
- Fundamentos de
async/awaitem Rust - Trabalho com a crate
tokio— o runtime assíncrono mais popular - Criação e combinação de
Future - Exemplos práticos: cliente HTTP assíncrono e timers
O artigo é voltado para desenvolvedores familiarizados com a sintaxe básica de Rust. Se você está começando agora — recomendamos primeiro estudar os fundamentos da linguagem no PythonLib.
Fundamentos de async/await e Future em Rust
O que é Future?
Future é uma trait que representa uma operação assíncrona que pode ser concluída no futuro. Em Rust, Future é lazy: ele não faz nada até ser consultado (poll). A consulta é responsabilidade do runtime assíncrono (por exemplo, Tokio).
Exemplo simples de uma função assíncrona:
use std::time::Duration;
async fn say_hello() { println!("Olá do mundo assíncrono!"); tokio::time::sleep(Duration::from_secs(1)).await; println!("Passou 1 segundo");}
#[tokio::main]async fn main() { say_hello().await;}A palavra-chave async transforma a função em um Future. A chamada .await pausa a execução da tarefa atual até a conclusão do Future, sem bloquear a thread.
Ciclo de vida de uma tarefa assíncrona
Quando você chama .await, acontece o seguinte:
- O runtime consulta o Future (chama o método
poll()) - Se o Future estiver pronto — o resultado é retornado
- Se o Future estiver esperando (por exemplo, uma operação de rede) — o runtime alterna para outra tarefa
- Quando o recurso se torna disponível, o runtime retoma a tarefa
Uma característica importante do Rust: .await só pode ser chamado dentro de uma função assíncrona ou bloco async {}. Tentar usá-lo em um contexto síncrono resultará em erro de compilação.
Trabalho prático com Tokio
Instalação e configuração
Tokio é um runtime assíncrono para Rust, fornecendo escalonador de tarefas, timers, sockets de rede e muito mais. Para começar, adicione ao Cargo.toml:
[dependencies]tokio = { version = "1", features = ["full"] }A flag features = ["full"] inclui todas as funcionalidades do Tokio. Para produção, é melhor selecionar apenas os recursos necessários.
Executando múltiplas tarefas assíncronas
Uma das principais vantagens da assincronia é a execução paralela de múltiplas tarefas. Use tokio::spawn para executar tarefas em segundo plano:
use tokio::time::{sleep, Duration};
async fn task(name: &str, seconds: u64) { println!("Tarefa {} iniciada", name); sleep(Duration::from_secs(seconds)).await; println!("Tarefa {} concluída após {} seg", name, seconds);}
#[tokio::main]async fn main() { let handle1 = tokio::spawn(task("A", 2)); let handle2 = tokio::spawn(task("B", 1));
// Aguarda a conclusão de ambas as tarefas let _ = tokio::join!(handle1, handle2); println!("Todas as tarefas concluídas");}A macro tokio::join! aguarda a conclusão de todos os Future passados. Se uma tarefa terminar antes, a execução não será interrompida — aguardaremos as restantes.