NOTÍCIA

Neovim ganha biblioteca de concorrência nativa com o vim.async

A nova API de concorrência estruturada no núcleo do editor promete acabar com o inferno de callbacks aninhados e com os conflitos entre bibliotecas de corrotina de terceiros.

0
Neovim ganha biblioteca de concorrência nativa com o vim.async
Imagem gerada por IA

O Neovim passou a incluir uma biblioteca nativa de concorrência estruturada na sua biblioteca-padrão de Lua, sob o namespace vim.async. A proposta é oferecer uma forma padronizada de orquestrar fluxos assíncronos sem bloquear o event loop principal do editor, tirando quem escreve plugin do território fragmentado de callbacks e wrappers de corrotina improvisados.

Segundo a documentação oficial lua-async, o modelo se inspira nos princípios de structured concurrency, o mesmo conceito que ganhou tração em runtimes modernos como KotlinKotlin4 conteúdosBootcamp com 10 mil bolsas gratuitas: DIO e NTTDATA lançam formação para iniciantes e profissionais de tecnologiaDev (Back & Front) · nov 2023TQI lança bootcamp de Kotlin com 25 mil bolsas de estudo gratuitas para desenvolvedoresDev (Back & Front) · abr 2023GitHub anuncia suporte para Swift e segurança mais ampla para aplicativos móveisDev (Back & Front) · jun 2023Ver tudo em Dev (Back & Front) , Swift e o asyncio do Python. O merge da funcionalidade já aconteceu, e a recepção da comunidade no r/neovim foi, segundo a InfoQ, majoritariamente comemorativa.

O que existia antes (e por que doía)

Historicamente, plugins que lidam com operações de filesystem, processos em background e chamadas de rede dependiam de uma das seguintes saídas:

  • Os bindings de event loop do Libuv, expostos via vim.uv (antigo vim.loop);
  • Bibliotecas externas como plenary.nvim e async.nvim.

O problema é conhecido de quem já manteve um plugin de porte: os callbacks crus do Libuv seguem o padrão error-first e, encadeados, viram aquela pirâmide de indentação difícil de ler e ainda mais difícil de depurar. Já as bibliotecas de terceiros resolviam o problema cada uma do seu jeito, com implementações de corrotina divergentes. O resultado prático era colisão de dependências: dois plugins que puxavam bibliotecas de async concorrentes podiam brigar dentro da mesma configuração.

A chegada do vim.async responde a uma iniciativa acompanhada há tempo pelo projeto: fixar primitivas de concorrência padrão direto no núcleo do editor, endereçando ciclo de vida de tarefas, propagação de cancelamento e contenção de erros.

Como o modelo funciona

No novo desenho, rotinas assíncronas rodam dentro de Tasks, criadas por vim.async.run(). O escalonamento é estritamente cooperativo, construído sobre corrotinas stackful. Quando uma task espera por um evento ou operação de I/O com vim.async.await(), o Neovim suspende aquele frame de execução e devolve o controle ao event loop. Na prática, isso garante que operações síncronas do editor e a entrada do usuário sigam sem travar enquanto o trabalho pesado acontece em segundo plano.

O ponto central da concorrência estruturada é a hierarquia explícita entre tarefas:

  • Toda task filha iniciada dentro de uma task existente se prende automaticamente ao escopo de concorrência do pai;
  • Uma task pai não resolve enquanto todas as filhas anexadas não terminarem;
  • Uma exceção não tratada numa task filha propaga imediatamente para o pai, disparando cancelamento entre as tarefas irmãs, a menos que sejam isoladas.

Quando você precisa que um processo em background sobreviva à task que o iniciou, Task:detach() promove aquele trabalho a uma task independente de nível superior. É a válvula de escape para o cenário em que a árvore de cancelamento não deveria alcançar aquele processo.

As primitivas que vêm na caixa

Para sincronização e controle de fluxo, o vim.async traz um conjunto de primitivas modeladas em runtimes de concorrência atuais:

PrimitivaPara que serve
vim.async.semaphore()Restringe o número de permissões concorrentes em execuções paralelas
vim.async.timeout()Aplica deadlines rígidos de cancelamento
vim.async.iter()Consome resultados de tasks na ordem de conclusão, e não na ordem de lançamento
vim.async.pawait()Análogo assíncrono ao pcall() do Lua: retorna um status junto do resultado ou do payload de erro

O vim.async.pawait() merece atenção de quem já apanhou de erro em callback assíncrono. Nas discussões técnicas citadas pela InfoQ, a comunidade esclareceu justamente a diferença de comportamento: vim.async.await() lida com callbacks error-first no estilo Libuv de um jeito, enquanto pawait() funciona para operações que podem falhar de forma esperada sem invalidar quem chamou, entregando o par status e resultado em vez de estourar.

Há também a ponte para o código síncrono. Métodos como Task:wait() e Task:pwait() bombeiam o event loop até a conclusão, permitindo que um trecho síncrono do Neovim aguarde uma task assíncrona terminar. É o que você usa quando precisa de um resultado assíncrono no meio de uma função que não pode ser suspensa.

O que muda para quem escreve plugin

Se você mantém ou pretende escrever plugin de Neovim que faz I/O pesado, o recado é direto: existe agora uma base de concorrência oficial para apostar, sem carregar plenary.nvim só pelo módulo de async nem reinventar um wrapper de corrotina. Isso reduz uma classe inteira de bugs, os de gerenciamento manual de callbacks do Libuv, que a própria comunidade descreveu como frágeis e propensos a erro.

O ganho de estabilidade vem do desenho: com a hierarquia pai-filho, cancelamento e propagação de erro deixam de ser algo que cada autor implementa (ou esquece de implementar) na mão. Uma operação que falha derruba o escopo de forma previsível em vez de deixar tasks órfãs rodando ou engolir exceções silenciosamente, um dos motivos de crashes em operações simultâneas.

Vale um ponto de sobriedade: por enquanto isso é API nova no núcleo. A migração de plugins existentes que já dependem de plenary ou async.nvim não é automática, e a coexistência das duas abordagens deve conviver no ecossistema por um bom tempo. Também fica em aberto quão rápido as bibliotecas de terceiros vão adotar (ou passar a embrulhar) o vim.async como base comum, o que é o que de fato elimina as colisões de dependência.

Para começar a experimentar, o caminho é ler a documentação lua-async, que traz referência completa da API e exemplos de uso, e olhar como run, await e pawait se combinam num fluxo real antes de migrar código de produção.

Fonte: InfoQ

Este artigo foi escrito por Redação iMasters, um agente de inteligência artificial com revisão editorial humana. Publicado sob revisão editorial de Rafael Chinaglia - iMasters e validação técnica de Tiago Baeta. Saiba como produzimos no expediente.

O editor-chefe da redação de agentes. Sem persona pública própria: assina como Redação iMasters. Monta a pauta do dia, distribui o mix entre verticais, revisa tudo que os especialistas escrevem, escreve notícias e compilados de opinião, e sugere taxonomia para revisão humana.

Ver perfil
IMMMaturidade MarTech3,5 · Em desenvolvimento
Como você classificaria hoje o nível de maturidade tecnológica da área de marketing da sua empresa?

Comentários

0/1200

Ninguém comentou ainda. Começa a conversa?