A chateação da minha existência: dar suporte tanto a código async quanto sync em Rust
Dar suporte a código síncrono e assíncrono em Rust expõe uma tensão mais profunda na programação moderna: uma vez que uma biblioteca adota I/O assíncrono, sua “cor” tende a se espalhar pela API, complicando o uso para chamadores que querem interfaces simples e bloqueantes. Os comentaristas contrastam o ecossistema de Rust — em que múltiplos runtimes, a falta de traits async padronizadas e restrições de feature flags tornam o suporte duplo a sync/async doloroso — com linguagens como Go, JavaScript, Python e Zig, cada uma embutindo diferentes trade-offs entre ergonomia, desempenho e complexidade de runtime. As alternativas propostas vão desde crates separados para sync/async e wrappers `block_on` até designs sans-I/O e systems de efeitos, mas nenhuma elimina totalmente o custo de manutenção e de design para autores de bibliotecas.
Dor em bibliotecas Rust: dar suporte a sync & async
- Problema central: bibliotecas querem oferecer APIs tanto síncronas quanto assíncronas sem duplicação de código, explosão de feature flags ou forçar um runtime async em usuários de sync.
- As regras de features do Cargo (“features devem ser aditivas”) tornam configurações mutuamente exclusivas sync/async desajeitadas.
- Manter dois crates (por exemplo,
-synce-async) ou dois caminhos de código paralelos foi tentado e considerado trabalhoso. - Usuários também não gostam de ser forçados ao async porque uma dependência assim escolheu.
Abordagens propostas
- Usar
block_onem uma thread dedicada para expor uma fachada sync sobre um núcleo async; muitos consideram isso um compromisso pragmático. - Manter apenas uma API async e sugerir que usuários sync bloqueiem sobre ela, embora isso ainda “colora” o chamador.
- Crates ou módulos separados para sync e async, com alguma discussão sobre nomenclatura.
- Estilo Sans-IO: expor tipos puros de request/response e deixar o chamador escolher clientes HTTP sync ou async.
- Macros / codegen (como o
unasyncdo Python ou ideias do tipo “multisync” do Nim) para gerar automaticamente variantes sync e async.
Async vs sync: debate conceitual
- Alguns veem async como “bonito” e a forma mais natural de expressar máquinas de estado complexas e I/O de alta concorrência.
- Outros acham futures e máquinas de estado menos naturais do que threads com escopo para muitas cargas de trabalho.
- Vários argumentam que os benefícios do async aparecem apenas quando muitas tarefas rodam em paralelo; para código puramente sequencial, ele adiciona sobrecarga mental.
- Há discordância sobre se async evita bugs de concorrência; outros apontam que condições de corrida ainda podem surgir quando
awaité inserido em código antes linear.
Comparações entre linguagens
- JS: async se integra suavemente porque I/O sempre foi baseado em callbacks e em thread única; esconder async sob sync ainda é difícil.
- Python: async abre novos padrões, mas
asyncioé criticado por ser pesado e às vezes mais lento do que threads simples. - Go: elogiado por um único modelo de concorrência “verde”; há debate sobre se isso realmente evita function coloring ou apenas padroniza uma única “cor”.
- Haskell: green threads e
asyncsão vistos como ergonomicamente mais agradáveis; a imutabilidade ajuda a raciocinar sobre concorrência.
Function coloring e runtimes
- “Function coloring” é amplamente citado como a dor de fundo: anotações async se propagam viralmente para cima na pilha de chamadas e entre módulos.
- A falta de um runtime embutido em Rust e a fragmentação entre Tokio e outros runtimes exacerbam a fricção (async traits, acoplamento ao runtime, semântica de cancelamento).
- Alguns esperam futuras soluções (keyword generics, effect systems, designs async-generic) para reduzir duplicação e tornar o código agnóstico ao runtime.
Imutabilidade, concorrência e bugs
- Um subthread argumenta que imutabilidade combina bem com async/threads ao eliminar data races; outros respondem que a imutabilidade pode ser supervalorizada e desloca a complexidade para mecanismos de atualização.
- Não há consenso; participantes trazem relatos tanto a favor quanto contra a imutabilidade como uma “bala de prata” para correção concorrente.