Traits AssĂ­ncronos

Métodos async em traits foram estabilizados apenas recentemente, no lançamento 1.75. Isso exigiu suporte para o uso de impl Trait em posição de retorno em traits, pois a "desaçucarização" para async fn inclui -> impl Future<Output = ...>.

No entanto, mesmo com o suporte nativo hoje, existem algumas armadilhas em torno de async fn e RPIT em _traits:

  • O impl Trait em posição de retorno captura todos os tempos de vida em escopo (portanto, alguns padrĂ”es de emprĂ©stimo nĂŁo podem ser expressos)

  • Os mĂ©todos de traits que usam impl trait em posição de retorno ou async nĂŁo sĂŁo compatĂ­veis com dyn.

Se precisarmos de suporte dyn, o crate async_trait fornece uma solução alternativa por meio de um macro, com algumas ressalvas:

use async_trait::async_trait;
use std::time::Instant;
use tokio::time::{sleep, Duration};

#[async_trait]
trait Sleeper {
    async fn sleep(&self);
}

struct FixedSleeper {
    sleep_ms: u64,
}

#[async_trait]
impl Sleeper for FixedSleeper {
    async fn sleep(&self) {
        sleep(Duration::from_millis(self.sleep_ms)).await;
    }
}

async fn run_all_sleepers_multiple_times(
    sleepers: Vec<Box<dyn Sleeper>>,
    n_times: usize,
) {
    for _ in 0..n_times {
        println!("executando todos os dormentes..");
        for sleeper in &sleepers {
            let start = Instant::now();
            sleeper.sleep().await;
            println!("dormiu por {}ms", start.elapsed().as_millis());
        }
    }
}

#[tokio::main]
async fn main() {
    let sleepers: Vec<Box<dyn Sleeper>> = vec![
        Box::new(FixedSleeper { sleep_ms: 50 }),
        Box::new(FixedSleeper { sleep_ms: 100 }),
    ];
    run_all_sleepers_multiple_times(sleepers, 5).await;
}
This slide should take about 5 minutes.
  • async_trait Ă© fĂĄcil de usar, mas observe que ele estĂĄ usando alocaçÔes de pilha para alcançar isso. Essa alocação de pilha impacta o desempenho.

  • Os desafios no suporte da linguagem para async trait sĂŁo profundos em Rust e provavelmente nĂŁo valem a pena descrever em detalhes. Niko Matsakis fez um bom trabalho ao explicĂĄ-los neste post se vocĂȘ estiver interessado em aprofundar.

  • Tente criar uma nova estrutura sleeper que dormirĂĄ por uma quantidade aleatĂłria de tempo e adicionĂĄ-la ao Vec.