20 pontos por carnoxen 2024-11-27 | 11 comentários | Compartilhar no WhatsApp

Resumo

Este é um texto escrito após acompanhar a disputa entre desenvolvedores Rust e desenvolvedores Linux tradicionais. Vários desenvolvedores podem ter estilos de código diferentes, mas o projeto Linux já tem um histórico de excluir C++ para evitar seu estilo e estrutura de código (RAII).

A forma como o código mencionada por Asahi Lina funciona é lenta demais ao encerrar esse programa e entra em conflito com o processamento em lote, que é a abordagem mais básica para criar software orientado a desempenho. Por exemplo, usar regiões de memória para processamento em lote permite coordenar várias lifetimes como uma só, então RAII não é necessário.

Aqui estão materiais que sustentam meu argumento. Todos eles explicam por que o processamento em lote é bom:

Portanto, acho que o Linux nunca deveria adotar RAII.


O motivo de eu trazer este texto é o seguinte. Vi várias vezes desenvolvedores Rust coreanos muito irritados ao ver esse texto, então fiquei curioso sobre o que as pessoas daqui pensam. O que vocês acham?

11 comentários

 
techiemann 2024-12-03

Na minha opinião, mas até consigo entender em certo grau o elitismo de certos desenvolvedores. Do ponto de vista da "engenharia" de software, especialmente no caso do Linux, hoje em dia é difícil encontrar um "software" que, no campo do open source, tenha dado as mãos de forma tão ampla até mesmo ao mundo fechado e ajudado no avanço da filosofia open source. Será que, por medo de que programadores não comprovados entrem em massa empunhando Rust, enchendo o projeto de código fora do controle do núcleo de mantenedores existentes, aumentando desenfreadamente a dívida técnica e encurtando o ciclo de vida do Linux, eles acabam mantendo uma postura conservadora que parece ainda mais excludente e até ludita?

É curioso adotar uma atitude nada "aberta" para que o open source continue sendo open source por muito tempo.

 
nullbus 2024-12-02

Eu também costumo usar e recomendar RAII ou formas semelhantes de gerenciamento de recursos com frequência. Isso porque, mesmo sem saber o que é RAII e usando de forma meio automática, ainda assim sai um código “ao menos seguro”.

No entanto, se não for usado com entendimento adequado, é muito fácil acabar produzindo em massa código ineficiente, como abrir e fechar dezenas de vezes um arquivo que poderia ser aberto apenas uma vez. Se o desenvolvedor mantém atenção constante ao desempenho e essa cultura é um pressuposto dentro da equipe de desenvolvimento, acredito que mesmo com RAII é possível obter um nível de desempenho plenamente suficiente.

 
aer0700 2024-11-30
  1. RAII: executar free sempre que cada objeto for destruído
  2. Execução em lote? Juntar o que precisa de free e executar em bulk?
    Existe alguma funcionalidade no Linux para fazer o 2 rodar mais rápido que o 1? Algo como uma API?
    Eu sempre vivi naturalmente com o 1, então não estou entendendo muito bem.
 
kandk 2024-11-29

Não quero voltar à experiência de desenvolvimento em que, depois de terminar tudo, eu precisava procurar vazamentos de memória com o valgrind.

 
kandk 2024-11-29

Não sei ao certo, mas dizer que não vai usar RAII parece significar que pretende melhorar o desempenho de close usando vazamento intencional de memória; não sei se é isso mesmo nem se essa é a direção certa.
De qualquer forma, se for um desenvolvedor que já sabe fazer bem o gerenciamento manual de memória, também vai saber usar RAII; e um desenvolvedor que não consegue programar sem RAII provavelmente também não vai conseguir gerenciar memória manualmente, então não vejo motivo para não usar RAII.

 
foriequal0 2024-11-29

Fiquei curioso sobre quanto tempo free consome, então fiz um teste com um código simples — embora seja bem diferente de uma carga real. (Usei build release de Rust, com std::alloc::alloc e std::fs::File.)
Alocando 10.000.000 blocos de memória de tamanhos variados, totalizando cerca de 2,5 GB, e medindo apenas o tempo de liberação, levou 1,87 segundo. Isso dá 187 ns por bloco.
Já no caso de arquivos, deixei abertos só uns 10.000 handles e medi apenas o tempo para fechá-los; deu cerca de 9 segundos. Ou seja, 900 us por arquivo.
(Neste PC com Windows, operações com arquivos são particularmente lentas, talvez por causa do antivírus. Em outro notebook com Windows, os números foram 400 ns/200 us, e em outro PC com Linux, 50 ns/600 ns.)

Como alternativa ao RAII, fala-se bastante em processamento em lote ou em confiar no SO no encerramento e vazar recursos de propósito; para memória, isso parece bem viável.
Mas, para recursos como arquivos ou sockets, nunca vi uma API de recuperação em lote, e se você vaza esses recursos, talvez o tempo no código de usuário diminua, mas o kernel acaba gastando praticamente esse mesmo tempo extra para encerrar o processo, então o ganho de desempenho é pequeno.

O RAII para memória também não é algo relativamente tão lento assim, nem é uma técnica que impossibilite o uso de arenas, nem impede vazamentos intencionais quando necessário; então me parece difícil usar isso como motivo para evitar RAII.
E, no caso do RAII de arquivos, que é ainda mais lento, como não há forma de tratar em lote nem de evitar o custo, fico curioso sobre o quanto as alternativas ao RAII realmente seriam melhores.


Um pouco fora do tema, mas tenho a impressão de que as objeções a RAII e lifetime costumam ser discutidas apenas no contexto de recursos de memória, representados por malloc/free.
RAII e lifetime são úteis não só para alocação de memória, mas de forma ampla para modelar a aquisição e devolução de recursos — e o controle de acesso exclusivo enquanto eles estão adquiridos — incluindo não só recursos do SO como arquivos, sockets e locks, mas também pools de objetos, pools de conexão etc.

Esses recursos também compartilham a mesma estrutura de malloc/free, então compartilham problemas estruturais como vazamento, use after free e double free.
E justamente por compartilharem essa mesma estrutura, acho que deveria haver mais destaque para o fato de que RAII e lifetime resolvem de uma vez não só problemas de memória, mas também os desses outros recursos.
Por exemplo, em Rust, até para file handles o compilador previne use after close e double close em tempo de compilação:
https://play.rust-lang.org/?version=stable&mode=debug&edition=…

As principais linguagens com GC gerenciam memória com GC, mas no fim ainda precisam introduzir, para recursos cujo gerenciamento precisa ser determinístico, como file handles e sockets, estruturas no estilo RAII (como o try-with-resources do Java, o using do C# e o with do Python) ou estruturas parecidas (como o defer do Go).
No fim, isso faz a linguagem ter vários modos diferentes de gerenciamento de recursos; me parece que algo assim talvez seja inferior a uma abordagem mais unificada.

 
crosh 2024-11-28
  1. É verdade que, ao excluir C++ do Linux, evitou-se o RAII, mas isso por si só não parece suficiente como evidência de que o Linux evitou C++ para evitar o RAII. Na carta do Linus que você apresentou, a palavra RAII não aparece.
  2. Para ser sincero, a partir do parágrafo que começa com “Asahi Lina...”, todos os links apresentados são vídeos do YouTube com dezenas de minutos de duração, então é difícil assistir. Acho que a discussão ficaria mais ativa se você trouxesse exemplos técnicos concretos, baseados em casos em que o RAII não é necessário.

Por exemplo, usar uma região de memória para fazer processamento em lote permite ajustar várias vidas úteis como uma só, então o RAII não é necessário.

Se com isso você quer dizer arena, então o Rust também naturalmente tem arena, e também é possível, ao eliminar a arena com lifetime, proibir o acesso aos elementos da arena depois de fazer a "liberação em lote". Consulte https://crates.io/keywords/arena .

 
ztaka 2024-11-28

Espero que surjam muitas linguagens mesmo depois de Zig e Rust. Mas, até agora, não vi nenhuma linguagem tão adequada quanto Rust. Na verdade, acho útil o conhecimento entre desenvolvedores que surge dessas discussões entre linguagens. Haha..

 
shoyuvanilla 2024-11-28

Eu também sou, à minha maneira, um desenvolvedor que usa Rust como linguagem principal, e não fiquei irritado, mas realmente me parece que estão recorrendo a um exemplo um pouco extremo ("o programa fica lento demais ao encerrar"; e, no vídeo linkado, citam um caso que não tem relação direta com exemplos em projetos Rust, e sim um caso em que o Visual Studio demora demais para fechar porque os destrutores de cada componente individual são chamados no encerramento).

Se, por questão de desempenho, for necessário processar de uma vez a limpeza de vários componentes, em vez de implementar Drop para cada componente individual, acho que dá para optar por implementar Drop em um tipo que detenha o tempo de vida desses componentes, para executar a limpeza de uma só vez. Melhor ainda se houver uma proteção para que esses componentes só possam ser criados por meio da API desse tipo.

Claro, me parece que a preocupação do autor do texto é que, se a prática de usar RAII entrar na base de código do Linux, pode acabar se acumulando, em uma base gigantesca e cheia de complexidade, código com preocupações de desempenho muito implícitas, e no longo prazo acontecer algo semelhante ao Visual Studio; acho que isso é, de fato, uma preocupação bem válida. Ainda assim, como você mencionou em outro comentário, também existe a segurança que o RAII oferece, então vejo a escolha mais como um trade-off.

 
cosine20 2024-11-28

Os dois lados estão dizendo coisas certas.

Fazendo uma analogia: no LoL, existe a percepção de que Azir é um campeão de tier alto, absurdamente bom em split push, controle de área em teamfights e valor da ultimate, mas isso só vale em partidas profissionais de altíssimo nível; no nível das pessoas comuns, ele é fraco demais na lane e também tem stats muito fracos, então acaba sendo apenas um campeão de tier baixíssimo.

Do ponto de vista de pessoas como Asahi Lina, que têm conhecimento de programação e de sistemas operacionais acima dos 10% do topo, é natural que alternativas além de RAII sejam melhores; mas, na parte com que os outros 90% lidam, acho que não há nada melhor do que RAII ou Rust.

No entanto, como um dos grandes motivos para precisar garantir estabilidade/segurança de memória são problemas de segurança... acho que esse trade-off é inevitável.

 
joonhwan 2024-11-28

Sem RAII, desenvolvedores com relativamente menos experiência provavelmente acabariam produzindo bugs em massa.

Fora do nível de SO, pelo menos no nível de aplicações...