Workstation resumo técnico: por que Rust continua a ser um forte padrão para muitas aplicações modernas — APIs, edge, agentes e plataformas CI/CD — e como colocar Ligado a CPU trabalhar corretamente ao lado de um tempo de execução assíncrono. Inspiramo-nos (não uma reimpressão literal) no ensaio de Alice Ryhl Async: O que é o bloqueio?, especialmente a orientação Rayon. Companheiro: notícias Evidência: Polyglot Benchmarks Relacionado: artigo poliglota.
- Bloqueio (sentido assíncrono): impedindo que o tempo de execução troque de tarefas — geralmente passando muito tempo sem
.await. - Correção ligada a CPU: preferem Rayon (ou um thread dedicado) em vez de rechear computação pesada em trabalhadores Tokio.
- Bibliotecas de sincronização vinculadas a IO:
tokio::task::spawn_blockingé geralmente a piscina certa. - Poliglota O Rust é uma ferramenta forte entre os pares — meça com Polyglot Benchmarks antes de exigir uma pilha.
- Crédito: enquadramento conceitual inspirado em Alice Ryhl / ryhl.io; Workstation o aplica à engenharia de plataformas.
1. Benefícios do Rust que são importantes nas unidades de produção
Portfólios de aplicativos modernos raramente são monolíngues. Ainda assim, certas superfícies recompensam as propriedades do Rust:
- Segurança de memória sem jitter GC — propriedade e empréstimo de captura uso-após-livre e corridas de dados em tempo de compilação; caminhos sensíveis à latência evitam pausas stop-the-world.
- Desempenho previsível — abstrações de custo zero e controle fino sobre a alocação tornam o Rust competitivo para caminhos API quentes e transformações de borda.
- Simultaneidade destemida (com estrutura) — Ecossistemas de envio/sincronização e assíncronos (Tokio, padrões de características assíncronas, canais) incentivam designs que escalam sob fan-out.
- Binários implantáveis — artefatos estáticos únicos simplificam os contêineres para gateways, agentes e sidecars CI/CD.
- Interoperabilidade em propriedades poliglotas — FFI, Wasm e HTTP mantêm o Rust ao lado das bordas Go, Python, JVM e Lua sem forçar uma reescrita de tudo.
A postura da Workstation corresponde à nossa Polyglot Benchmarks blog and long article: choose the right tool for the bounded context. On the live dashboard at polyglot-benchmarks.fictionally.org, Rust (Actix in that harness) frequently shows strength on CPU-bound and concurrency-sensitive HTTP rows — useful evidence when an ADR argues for Rust on a hot path, not a religion.
2. Cooperative scheduling: the meaning of “blocking”
Async Rust uses cooperative scheduling. The runtime swaps tasks when they reach an .await. Alice Ryhl’s memorable rule applies everywhere we ship async services:
Async code should never spend a long time without reaching an .await.
In this vocabulary, “blocking the thread” does not merely mean “doing IO.” It means evitando que o tempo de execução troque a tarefa atual. Classic footguns:
std::thread::sleepinside an async fn (no await — timers run serially underjoin!).- Heavy loops, compression, crypto, vector math, or JSON-on-steroids on a Tokio worker.
- Holding a sync mutex across a long critical section on the async pool (short locks can be fine; long ones are not).
Em um tempo de execução multithread, você pode ocultar o bug até saturar os threads de trabalho. O tráfego de produção encontra isso para você. Para SLOs de latência, trate dezenas a centenas de microssegundos entre esperas como o orçamento para trabalho cooperativo; qualquer coisa mais pertence ao pool assíncrono.
3. Three places to put work that must block
Quando você precisar bloquear intencionalmente – CPU caro ou sincronizar IO – mova esse trabalho para fora dos threads do agendador do Tokio. A folha de dicas (alinhada com o enquadramento de Ryhl):
| Approach | Ligado a CPU | Sync IO | Runs forever |
|---|---|---|---|
spawn_blocking | Abaixo do ideal (piscina grande) | OK | No |
| Rayon | OK | No | No |
Dedicated std::thread | OK | OK | OK |
3.1 spawn_blocking for sync IO
tokio::task::spawn_blocking schedules onto Tokio’s blocking pool (hundreds of threads by default). That suits filesystem calls and blocking database drivers. It is a poor fit for sustained CPU because oversubscription fights the OS scheduler — fine for a few short computations, risky as a default for parallel crunching.
3.2 Rayon for expensive CPU
Rayon maintains a pool sized for CPU-bound parallelism. The critical integration detail: do não block a Tokio worker waiting for Rayon. Spawn on Rayon, send the result through tokio::sync::oneshot, and .await the receiver on the async side. Parallel iterators (par_iter) ainda precisa daquele exterior rayon::spawn because they block until complete.
// Shape only — see ryhl.io for a full walkthrough
async fn parallel_work(data: Vec<i32>) -> i32 {
let (tx, rx) = tokio::sync::oneshot::channel();
rayon::spawn(move || {
let sum: i32 = data.into_iter().sum(); // or par_iter inside
let _ = tx.send(sum);
});
rx.await.expect("rayon task panicked")
}
Credit: this integration pattern is the heart of the Rayon crate section on ryhl.io. Workstation recommends the same shape inside product services so request threads stay schedulable.
3.3 Dedicated threads for forever work
A loop that never exits (dedicated DB connection owner, long-lived bridge) should not consume a slot from either pool permanently. Prefer std::thread::spawn and communicate via channels.
4. Mapping the advice onto modern application types
| Surface | Keep on async | Offload |
|---|---|---|
| APIs | Accept, authn, fan-out HTTP, streaming | Heavy serialization, crypto batches, scoring |
| Edge / gateways | Routing, cache lookup, WAF decisions | Rare CPU transforms; prefer Lua/njs when measured better |
| Agents | Tool orchestration, MCP sessions, timeouts | Embedding prep, eval suites, large local transforms |
| CI/CD platforms | Promote APIs, health polls, UI/API | Deep artifact analysis, bulk verification |
Workstation products illustrate the split: Ring Promoter must keep promotion and health gates snappy; WSL Proxy keeps edge paths free; KubePilot needs responsive incident loops even when analysis is heavy. Rust (or Go, or Lua) is chosen per surface after measurement — never because a hallway debate declared a winner.
5. Architecture checklist for teams adopting async Rust
- Inventory await gaps: profilers and tracing spans that never yield.
- Classify blocking work: sync IO vs CPU vs forever-loop.
- Pick the pool:
spawn_blocking, Rayon + oneshot, or dedicated thread. - Load-test with realistic concurrency — multi-threaded runtimes hide bugs at N=1.
- Document the decision in an ADR; attach Polyglot Benchmarks rows when language choice is in play.
- Re-read Tokio guidance on shared state and cooperative yielding for tail latency.
6. Further reading
- Alice Ryhl — Async: O que é o bloqueio? (primary inspiration for the Rayon / spawn_blocking framing).
- Workstation — Polyglot Benchmarks live dashboard.
- Workstation — Polyglot blog · Polyglot article.
- Workstation — blog complementar for a skim version of this brief.
Published by Workstation. Conceptual credit to Alice Ryhl’s public writing on async blocking and Rayon; all product framing and polyglot guidance are Workstation’s.