- Na comunidade Rust, aparece com frequência a pergunta: se threads conseguem fazer tudo o que
async/await faz e de forma mais simples, por que escolher async/await?
- Rust é uma linguagem de baixo nível e não esconde a complexidade das corrotinas. Isso é o oposto de linguagens como Go, que funcionam de forma assíncrona por padrão sem exigir que o programador pense em assincronicidade.
- Programadores inteligentes tentam evitar complexidade, então por que
async/await é necessário?
Entendendo o contexto
- Rust é uma linguagem de baixo nível. O código geralmente é linear, e uma tarefa só é executada depois que a outra termina.
- Quando é preciso executar muitas tarefas ao mesmo tempo, como em um servidor web, o código linear passa a ser um problema.
- A web inicial tentou resolver isso introduzindo threading.
- Com threads, é possível atender vários clientes simultaneamente, mas os programadores também quiseram trazer a concorrência do espaço do sistema operacional para o espaço do usuário.
O problema do timeout
- Uma das maiores vantagens do Rust é a composabilidade.
async/await permite aplicar essa composabilidade a funções limitadas por I/O.
- Por exemplo, ao querer adicionar um timeout a uma função de atendimento de cliente, isso pode ser implementado usando dois combinadores.
Threads temáticas
- Em um exemplo usando threads, implementar timeout não é algo simples.
TcpStream tem as funções set_read_timeout e set_write_timeout, mas o uso delas é limitado.
- O artigo mostra uma forma de programar timeout usando os combinadores do Rust, mas isso fica restrito a
TcpStream e ainda exige chamadas de sistema adicionais.
Casos de sucesso de async
- O ecossistema HTTP adotou
async/await como principal mecanismo de runtime.
tower é um exemplo que mostra a força de async/await, oferecendo timeout, limitação de taxa, balanceamento de carga e mais.
macroquad é uma engine de jogos em Rust que executa a engine usando async/await.
Melhorando a imagem do async
- Como as vantagens de
async não são amplamente conhecidas, algumas pessoas podem entendê-lo mal.
- A comunidade Rust tende a superestimar os ganhos de desempenho do Rust assíncrono e a minimizar seus benefícios realmente significativos.
async/await deve ser visto como um modelo de programação poderoso, capaz de expressar de forma concisa padrões que, em Rust síncrono, não podem ser representados sem dezenas de threads e canais.
Opinião do GN⁺
async/await aumenta a complexidade do código ao lidar com concorrência, mas ao mesmo tempo oferece a capacidade de atender muitos clientes com eficiência.
- Este artigo destaca que
async/await tem pontos fortes no modelo de programação, e não apenas vantagens de desempenho.
- O
async/await do Rust oferece composabilidade para vários tipos de trabalho de I/O, o que é especialmente útil em áreas como serviços de rede e servidores web.
- Sob uma visão crítica, a complexidade de
async/await pode ser uma barreira de entrada para desenvolvedores iniciantes, e é preciso esforço educacional para superar isso.
- Outros projetos com funcionalidade semelhante incluem a implementação de
async/await do Node.js e a biblioteca asyncio do Python, que também oferecem paradigma parecido.
- Ao adotar
async/await, é preciso considerar a complexidade e a manutenibilidade do código; ainda assim, quando é necessário atender muitos clientes ao mesmo tempo, esse modelo oferece grandes vantagens.
1 comentários
Comentários do Hacker News
Async/await e thread única
Mutexpadrão e os canaiscrossbeam-channelsão injustos.Async/await versus threads
Problemas no artigo
Pontos que não foram abordados
Ponto importante sobre cancelamento
Uma campanha quase de marketing em torno de async/await
Async/await versus fibras
Principais vantagens do async/await em Rust
Mal-entendidos sobre async/await
Por que escolher async/await em vez de threads