💻 Exemplos: Capítulo 18: Programação Assíncrona com Runtime Tokio

Especialização em Sistemas com Rust • Demonstrações Práticas Compiláveis


🎯 Objetivo dos Exemplos

Apresentar a programação assíncrona orientada a eventos no Rust de alta performance: o modelo de Future baseado em polling, configuração do runtime multithread com #[tokio::main], despacho de tarefas não-bloqueantes com tokio::spawn, canais assíncronos de alta vazão e multiplexação com a macro tokio::select!.


1. Manifesto Cargo.toml com Dependências do Tokio

[package]
name = "servidor_assincrono_tokio"
version = "0.1.0"
edition = "2021"

[dependencies]
tokio = { version = "1.38", features = ["full"] }

2. Código Fonte Completo (src/main.rs)

//! Servidor Assíncrono Concorrente com Tokio Runtime e Multiplexação

use std::time::Duration;
use tokio::sync::mpsc;
use tokio::time::sleep;

#[derive(Debug)]
struct PacoteTelemetria {
    origem: String,
    valor_kwh: f64,
}

/// Simula uma requisição HTTP ou leitura de socket assíncrona não bloqueante
async fn buscar_metrica_sensor(id: &str, latencia_ms: u64) -> PacoteTelemetria {
    // sleep do Tokio cede a thread para outras tarefas (cooperative multitasking)
    sleep(Duration::from_millis(latencia_ms)).await;
    PacoteTelemetria {
        origem: format!("SENSOR_{}", id),
        valor_kwh: 45.2 + (latencia_ms as f64 * 0.1),
    }
}

/// Processo de timeout e heartbeat concorrente com tokio::select!
async fn monitorar_canal_com_timeout(mut rx: mpsc::Receiver<PacoteTelemetria>) {
    loop {
        tokio::select! {
            // Ramo 1: Recebe dados do canal assíncrono
            Some(pacote) = rx.recv() => {
                println!("  [RECEBIDO VIA TOKIO] Origem: {:<12} | Leitura: {:.2} kWh", pacote.origem, pacote.valor_kwh);
            }

            // Ramo 2: Dispara se não houver dados por mais de 100ms
            _ = sleep(Duration::from_millis(100)) => {
                println!("  [TIMEOUT DE SILÊNCIO] Nenhum pacote nos últimos 100ms. Verificando saúde do runtime...");
                break;
            }
        }
    }
}

#[tokio::main]
async fn main() {
    println!("=== RUNTIME ASSÍNCRONO TOKIO DE ALTA PERFORMANCE ===");
    println!("Iniciando Tokio Reactor Multithread...");

    // 1. Canal assíncrono Tokio com buffer de 32 mensagens
    let (tx, rx) = mpsc::channel::<PacoteTelemetria>(32);

    // 2. Disparando tarefas assíncronas concorrentes (Green Tasks)
    // Uma thread do SO pode orquestrar centenas de milhares de tarefas Tokio!
    let tx1 = tx.clone();
    tokio::spawn(async move {
        let p = buscar_metrica_sensor("GRID_NORTE", 30).await;
        tx1.send(p).await.expect("Falha ao enviar pacote Norte");
    });

    let tx2 = tx.clone();
    tokio::spawn(async move {
        let p = buscar_metrica_sensor("GRID_SUL", 60).await;
        tx2.send(p).await.expect("Falha ao enviar pacote Sul");
    });

    // Descartamos o transmissor original para permitir que o canal finalize
    drop(tx);

    // 3. Executando o consumidor assíncrono com monitoramento de timeout
    monitorar_canal_com_timeout(rx).await;

    println!("Runtime Tokio liberado e finalizado com sucesso!");
}

3. Saída Esperada no Terminal

=== RUNTIME ASSÍNCRONO TOKIO DE ALTA PERFORMANCE ===
Iniciando Tokio Reactor Multithread...
  [RECEBIDO VIA TOKIO] Origem: SENSOR_GRID_NORTE | Leitura: 48.20 kWh
  [RECEBIDO VIA TOKIO] Origem: SENSOR_GRID_SUL   | Leitura: 51.20 kWh
  [TIMEOUT DE SILÊNCIO] Nenhum pacote nos últimos 100ms. Verificando saúde do runtime...
Runtime Tokio liberado e finalizado com sucesso!