---
title: "Async/Await Básico em Rust"
url: "https://rustlang.com.br/receitas/async-await-basico/"
markdown_url: "https://rustlang.com.br/receitas/async-await-basico.MD"
description: "Aprenda async/await em Rust com tokio. Runtime assíncrono, async fn, .await, join!, select!, e exemplos completos de concorrência assíncrona."
date: "2026-02-23"
author: "Equipe Rust Brasil"
---

# Async/Await Básico em Rust

Aprenda async/await em Rust com tokio. Runtime assíncrono, async fn, .await, join!, select!, e exemplos completos de concorrência assíncrona.


# Async/Await Básico em Rust

A programação assíncrona em Rust permite executar muitas tarefas de I/O concorrentemente sem o custo de criar threads do sistema operacional. O runtime `tokio` é o mais popular e robusto do ecossistema.

## Dependências

**Cargo.toml:**
```toml
[dependencies]
tokio = { version = "1", features = ["full"] }
```

## Primeira função assíncrona

Uma função `async` retorna uma `Future` que precisa ser executada por um runtime:

```rust
use std::time::Duration;
use tokio::time::sleep;

// Funções async retornam implicitamente uma Future
async fn saudacao(nome: &str) -> String {
    // .await pausa esta função até o sleep completar
    sleep(Duration::from_millis(100)).await;
    format!("Olá, {}!", nome)
}

async fn calcular(x: i32, y: i32) -> i32 {
    sleep(Duration::from_millis(50)).await;
    x + y
}

// #[tokio::main] cria o runtime e executa a função async
#[tokio::main]
async fn main() {
    println!("Início");

    let msg = saudacao("Rust").await;
    println!("{}", msg);

    let resultado = calcular(20, 22).await;
    println!("20 + 22 = {}", resultado);

    println!("Fim");
}
```

**Saída:**
```
Início
Olá, Rust!
20 + 22 = 42
Fim
```

## Executar tarefas em paralelo com `join!`

O macro `join!` executa múltiplas futures concorrentemente:

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

async fn buscar_usuario() -> String {
    sleep(Duration::from_millis(200)).await;
    "Maria Silva".to_string()
}

async fn buscar_pedidos() -> Vec<String> {
    sleep(Duration::from_millis(300)).await;
    vec!["Pedido #1".to_string(), "Pedido #2".to_string()]
}

async fn buscar_saldo() -> f64 {
    sleep(Duration::from_millis(150)).await;
    1500.50
}

#[tokio::main]
async fn main() {
    // Sequencial — cada await bloqueia o próximo
    let inicio = Instant::now();
    let _usuario = buscar_usuario().await;
    let _pedidos = buscar_pedidos().await;
    let _saldo = buscar_saldo().await;
    println!("Sequencial: {:?}", inicio.elapsed());

    // Paralelo com join! — todas executam ao mesmo tempo
    let inicio = Instant::now();
    let (usuario, pedidos, saldo) = tokio::join!(
        buscar_usuario(),
        buscar_pedidos(),
        buscar_saldo()
    );
    println!("Paralelo: {:?}", inicio.elapsed());

    println!("\nUsuário: {}", usuario);
    println!("Pedidos: {:?}", pedidos);
    println!("Saldo: R${:.2}", saldo);
}
```

**Saída:**
```
Sequencial: 650ms
Paralelo: 300ms

Usuário: Maria Silva
Pedidos: ["Pedido #1", "Pedido #2"]
Saldo: R$1500.50
```

## Spawn de tarefas com `tokio::spawn`

Lance tarefas assíncronas independentes:

```rust
use tokio::time::{sleep, Duration};

async fn processar_item(id: u32) -> String {
    sleep(Duration::from_millis(100 * id as u64)).await;
    format!("Item {} processado", id)
}

#[tokio::main]
async fn main() {
    // Criar várias tarefas assíncronas
    let mut handles = Vec::new();

    for id in 1..=5 {
        // tokio::spawn lança uma tarefa no runtime
        let handle = tokio::spawn(async move {
            let resultado = processar_item(id).await;
            println!("  {}", resultado);
            resultado
        });
        handles.push(handle);
    }

    // Coletar resultados
    let mut resultados = Vec::new();
    for handle in handles {
        let resultado = handle.await.unwrap();
        resultados.push(resultado);
    }

    println!("\nTodos processados: {} tarefas", resultados.len());
}
```

**Saída:**
```
  Item 1 processado
  Item 2 processado
  Item 3 processado
  Item 4 processado
  Item 5 processado

Todos processados: 5 tarefas
```

## `select!` — responder à primeira future

O macro `select!` executa múltiplas futures e age na primeira que completar:

```rust
use tokio::time::{sleep, Duration};

async fn servidor_principal() -> String {
    sleep(Duration::from_millis(300)).await;
    "Resposta do servidor principal".to_string()
}

async fn servidor_backup() -> String {
    sleep(Duration::from_millis(200)).await;
    "Resposta do servidor backup".to_string()
}

async fn timeout_seguranca() {
    sleep(Duration::from_millis(500)).await;
}

#[tokio::main]
async fn main() {
    // Pegar a resposta mais rápida
    let resultado = tokio::select! {
        resp = servidor_principal() => {
            println!("Principal respondeu primeiro");
            resp
        }
        resp = servidor_backup() => {
            println!("Backup respondeu primeiro");
            resp
        }
        _ = timeout_seguranca() => {
            println!("Timeout!");
            "Nenhum servidor respondeu".to_string()
        }
    };

    println!("Resultado: {}", resultado);
}
```

**Saída:**
```
Backup respondeu primeiro
Resultado: Resposta do servidor backup
```

## Timeout em operações assíncronas

Adicione limites de tempo às suas operações:

```rust
use std::time::Duration;
use tokio::time::{sleep, timeout};

async fn operacao_lenta() -> String {
    sleep(Duration::from_secs(5)).await;
    "Concluído!".to_string()
}

async fn operacao_rapida() -> String {
    sleep(Duration::from_millis(100)).await;
    "Rápido!".to_string()
}

#[tokio::main]
async fn main() {
    // Operação com timeout
    match timeout(Duration::from_secs(1), operacao_lenta()).await {
        Ok(resultado) => println!("Sucesso: {}", resultado),
        Err(_) => println!("Timeout! Operação demorou mais de 1 segundo"),
    }

    // Operação que completa a tempo
    match timeout(Duration::from_secs(1), operacao_rapida()).await {
        Ok(resultado) => println!("Sucesso: {}", resultado),
        Err(_) => println!("Timeout!"),
    }
}
```

**Saída:**
```
Timeout! Operação demorou mais de 1 segundo
Sucesso: Rápido!
```

## Canais assíncronos com `mpsc`

Comunique entre tarefas assíncronas:

```rust
use tokio::sync::mpsc;
use tokio::time::{sleep, Duration};

#[derive(Debug)]
struct Mensagem {
    remetente: String,
    conteudo: String,
}

#[tokio::main]
async fn main() {
    let (tx, mut rx) = mpsc::channel::<Mensagem>(32); // buffer de 32

    // Produtores
    for i in 1..=3 {
        let tx = tx.clone();
        tokio::spawn(async move {
            for j in 1..=2 {
                let msg = Mensagem {
                    remetente: format!("Produtor {}", i),
                    conteudo: format!("Mensagem {}", j),
                };
                tx.send(msg).await.unwrap();
                sleep(Duration::from_millis(50 * i as u64)).await;
            }
        });
    }

    // Dropar transmissor original
    drop(tx);

    // Consumidor
    let mut total = 0;
    while let Some(msg) = rx.recv().await {
        println!("[{}] {}", msg.remetente, msg.conteudo);
        total += 1;
    }

    println!("\nTotal recebido: {} mensagens", total);
}
```

**Saída (ordem pode variar):**
```
[Produtor 1] Mensagem 1
[Produtor 2] Mensagem 1
[Produtor 3] Mensagem 1
[Produtor 1] Mensagem 2
[Produtor 2] Mensagem 2
[Produtor 3] Mensagem 2

Total recebido: 6 mensagens
```

## Quando usar threads vs async

| Cenário | Melhor opção |
|---------|-------------|
| Muitas conexões de rede | `async/await` (tokio) |
| Cálculos pesados (CPU) | `std::thread` ou `rayon` |
| Leitura de muitos arquivos | `async/await` (tokio) |
| Processamento de imagens | `rayon` (thread pool) |
| Servidor web | `async/await` (axum/tokio) |
| Parser de dados grandes | `rayon` para paralelismo de dados |

## Veja também

- [Executar Threads](/receitas/executar-threads/) — concorrência com threads do SO
- [Fazer Requisição HTTP](/receitas/fazer-requisicao-http/) — uso prático de async com reqwest
- [Criar Servidor HTTP](/receitas/criar-servidor-http/) — servidor web assíncrono com axum
- [Conectar ao PostgreSQL](/receitas/conectar-postgresql/) — queries assíncronas ao banco
- [Ler Arquivo em Rust](/receitas/ler-arquivo/) — I/O de arquivo (sync vs async)
- Documentação da crate: [tokio](https://docs.rs/tokio/)
