Noções Básicas de Tokio
9 exemplos para você começar com Tokio - 6 básicos e 3 intermediários.
Pré-requisitos
- Rust 1.97.0 (edição 2024).
tokio = { version = "1", features = ["full"] }emCargo.toml.
Exemplos Básicos
1. #[tokio::main]
O atributo instala um runtime multi-thread e gerencia main.
#[tokio::main]
async fn main() {
println!("Tokio está rodando");
}- Expande para
Runtime::new()+block_on. - O sabor padrão é multi-threaded.
- Use
async fn mainapenas com um atributo de runtime oublock_onmanual.
Relacionado: Executors & Runtimes - detalhes internos do runtime
2. Spawn de Tarefas
tokio::spawn agenda trabalho independente no runtime.
#[tokio::main]
async fn main() {
let handle = tokio::spawn(async {
100
});
println!("{}", handle.await.unwrap());
}- Retorna
JoinHandle<T>- um future que você aguarda pelo resultado. - Tarefas "spawnadas" devem ser
'staticeSend(runtime multi-thread). - Panics em tarefas se propagam como
JoinErrorao aguardar.
Relacionado: Tasks & JoinHandles - ciclo de vida
3. Async Sleep
Atrasos cooperativos sem bloquear threads.
use tokio::time::{sleep, Duration};
#[tokio::main]
async fn main() {
println!("início");
sleep(Duration::from_millis(100)).await;
println!("fim");
}sleepcede a thread de trabalho para outras tarefas.- Requer o driver de tempo do Tokio habilitado.
- Prefira sobre
std::thread::sleepem código async.
Relacionado: Timers & Intervals - timers
4. TcpListener Echo
Tokio fornece primitivas de rede assíncronas.
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::TcpListener;
#[tokio::main]
async fn main() -> std::io::Result<()> {
let listener = TcpListener::bind("127.0.0.1:0").await?;
let addr = listener.local_addr()?;
tokio::spawn(async move {
let (mut socket, _) = listener.accept().await.unwrap();
let mut buf = [0u8; 32];
let n = socket.read(&mut buf).await.unwrap();
socket.write_all(&buf[..n]).await.unwrap();
});
let mut stream = tokio::net::TcpStream::connect(addr).await?;
stream.write_all(b"ping").await?;
Ok(())
}bindeacceptsão assíncronos - sem threads bloqueadas esperando.- Cada conexão geralmente recebe sua própria tarefa "spawnada".
- Axum é construído sobre a pilha de rede do Tokio.
Relacionado: Async I/O - guia completo de I/O
5. Canal mpsc
Canais Tokio são cientes de async.
use tokio::sync::mpsc;
#[tokio::main]
async fn main() {
let (tx, mut rx) = mpsc::channel(4);
tx.send(1).await.unwrap();
tx.send(2).await.unwrap();
drop(tx);
while let Some(n) = rx.recv().await {
println!("{n}");
}
}- Capacidade limitada aplica backpressure em
send().await. recv().awaitespera sem bloquear threads do SO.- Solte todos os remetentes para fechar o canal.
Relacionado: Canais em Tokio - todos os tipos de canal
6. spawn_blocking
Descarrega chamadas de sistema bloqueantes das threads de trabalho.
#[tokio::main]
async fn main() {
let len = tokio::task::spawn_blocking(|| {
std::fs::metadata("/etc/hosts").map(|m| m.len())
})
.await
.unwrap()
.unwrap();
println!("{len}");
}- Executa no pool de threads bloqueantes do Tokio.
- Essencial para APIs síncronas legadas em servidores assíncronos.
- Prefira
tokio::fsquando a API de arquivo assíncrona for suficiente.
Relacionado: Bloqueio em Async - quando e como
Exemplos Intermediários
7. Multiplexador select!
Corrida de múltiplas operações assíncronas.
use tokio::time::{sleep, Duration};
#[tokio::main]
async fn main() {
tokio::select! {
_ = sleep(Duration::from_millis(50)) => println!("timer"),
_ = async { sleep(Duration::from_millis(10)).await } => println!("rápido"),
}
}- O primeiro branch concluído vence; os outros são cancelados.
- Comum para sinais de desligamento + loops de trabalho.
- Leia a documentação de segurança contra cancelamento para cada tipo de branch.
Relacionado: select! & Concorrência - padrões
8. Estado Compartilhado Estilo Axum
Arc clona de forma barata para handlers e tarefas.
use std::sync::Arc;
#[derive(Clone)]
struct AppState {
label: Arc<String>,
}
#[tokio::main]
async fn main() {
let state = AppState {
label: Arc::new("api".into()),
};
let task_state = state.clone();
tokio::spawn(async move {
println!("{}", task_state.label);
})
.await
.unwrap();
}CloneemAppStateclona ponteirosArc, não strings.- Armazene pools e clientes no estado na inicialização.
- Veja a página Shared State para padrões de mutex vs ator.
Relacionado: Estado Compartilhado em Async - padrões
9. Esboço de Desligamento Gracioso
Ouça o ctrl-c e processe tarefas pendentes.
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tokio::select! {
_ = tokio::signal::ctrl_c() => println!("desligando"),
_ = async {
tokio::time::sleep(std::time::Duration::from_secs(3600)).await;
} => {}
}
Ok(())
}ctrl_c()integra-se ao tratamento de sinais do Tokio.- Servidores de produção processam requisições em andamento antes de sair.
- Use
CancellationTokenpara árvores de tarefas filhas.
Relacionado: Desligamento Gracioso - guia de produção
Versões da Stack: Esta página foi escrita para Rust 1.97.0 (edição 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, e Polars 0.46+.