1 pontos por GN⁺ 2023-12-26 | 1 comentários | Compartilhar no WhatsApp
  • O YJIT melhora significativamente o desempenho e o uso de memória em relação ao Ruby 3.2, ficando mais de 3 vezes mais rápido que o interpretador no Optcarrot
  • O Code GC do YJIT passa a vir desativado por padrão, e --yjit-exec-mem-size funciona como um limite rígido que interrompe a compilação de novo código
  • A adição de RubyVM::YJIT.enable permite ativar o YJIT em tempo de execução sem alterar argumentos de linha de comando nem variáveis de ambiente
  • O parser Prism foi adicionado como gem padrão, com disponibilidade das APIs Prism.parse(source), Prism.parse_comments(source) e Prism.parse_success?(source)
  • É possível testar o compilador Prism com ruby --parser=prism ou RUBYOPT="--parser=prism", mas essa flag é destinada apenas a depuração
  • O gerador de parser foi trocado de Bison para Lrama, e o parser interno do Lrama foi substituído por um parser LR gerado pelo Racc para facilitar a manutenção
  • O compilador JIT pure-Ruby RJIT substitui o MJIT, mas oferece suporte apenas à arquitetura x86-64 no Unix e permanece restrito a fins experimentais
  • Foi introduzido o escalonador de threads M:N, em que N threads nativas gerenciam M threads Ruby, mas ele vem desativado por padrão no Ractor principal porque pode quebrar a compatibilidade com extensões C
  • O uso de it chamado sem argumentos e em blocos sem parâmetros ordinários entra em descontinuação (deprecation) e, no Ruby 3.4, passará a se referir ao primeiro parâmetro do bloco
  • Regexp::new agora aceita no máximo 2 argumentos, em vez da chamada com 3 argumentos que foi descontinuada no Ruby 3.2
  • ext/readline foi aposentado e, daqui para frente, passará a depender de reline, uma implementação em Ruby puro compatível com a API de ext/readline
  • Se ext/readline for necessário, ele pode ser instalado a partir do rubygems.org com gem install readline-ext, sem exigir mais a instalação de bibliotecas como libreadline ou libedit
  • RubyGems e Bundler passam a emitir aviso ao usar require com alguns gems sem adicioná-los ao Gemfile ou ao gemspec, e esses gems passarão a ser bundled gems em versões futuras do Ruby
  • Ao usar o gem bootsnap, esse aviso é suprimido e, por causa de uma limitação desta versão, recomenda-se executar a aplicação pelo menos uma vez com a variável de ambiente DISABLE_BOOTSNAP=1
  • O prism 0.19.0 foi adicionado como gem padrão, e o racc 1.7.3 foi promovido de default gem para bundled gem

1 comentários

 
GN⁺ 2023-12-26
Opiniões no Hacker News
  • Vejo que, com o Ruby 3.3, Ruby voltou com força. Uma linguagem focada na felicidade do desenvolvedor, mas que era ridicularizada por ser lenta, agora já não é mais lenta
    YJIT é uma tecnologia impressionante e, junto com object shapes e várias otimizações de garbage collection, o Ruby está ficando bem rápido. Grandes usuários de Ruby, como a Shopify, também ativaram o YJIT em produção com pré-releases do 3.3 e relataram melhorias de desempenho de dois dígitos percentuais
    Pessoalmente, estou muito empolgado com o Ruby e seu futuro, e quero trabalhar com o Ruby 3.3 e aplicá-lo em sites de clientes em produção
    https://railsatscale.com/2023-09-18-ruby-3-3-s-yjit-runs-sho...

    • Não sei se um pequeno ganho de desempenho faria alguém escolher Ruby do zero, mas é bom ver melhorias incrementais. Preocupar-se demais com desempenho é quase sempre otimização prematura, e o Ruby sempre foi rápido o bastante para as tarefas que exigimos dele
      Também o usei como código de integração entre um armazenamento de registros DNS baseado em Redis e o PowerDNS; a pilha inteira processava 500 milhões de consultas por mês em 14 VPS pequenas sem nem aparecer no htop. Não usei PowerDNS por desempenho, mas porque geralmente não é uma boa ideia implementar por conta própria coisas expostas à internet pública, como criptografia, HTTP e DNS
      A ironia da web hoje é que webapps feitos com o “lento” Ruby e renderização no servidor carregam páginas mais rápido do que bancos de dados de consistência eventual realmente lentos e webapps de frontend inchados. Na web moderna, vemos spinners de carregamento com frequência demais até para fazer coisas triviais
    • A linguagem Ruby em si pode ser rápida, mas todo o ecossistema é dolorosamente lento. Quando construímos em Rails um servidor que retornava 1 MB de JSON por requisição, passando por consultas ao banco de dados e chamadas a outros serviços, chegávamos a cerca de 100 requisições por segundo; ao reescrever o mesmo serviço em Go, ele processou 100 mil requisições por segundo
    • Fiquei curioso se “melhoria de desempenho de dois dígitos” significava 10% mais rápido ou 10 vezes mais rápido
      Ao abrir o link, vi que era uma melhoria na casa dos 10%. Não acho que isso vá mudar muito a percepção de que Ruby é aproximadamente 50 a 200 vezes mais lento que linguagens “rápidas” como Rust, Java, Go e C++
    • Uma área em que o Ruby poderia melhorar a experiência do desenvolvedor é uma experiência de depuração melhor. Talvez por eu estar muito acostumado ao Chrome DevTools, mas da última vez que depurei código Ruby com muita metaprogramação, foi doloroso entender o que estava acontecendo
    • Ao ouvir “dois dígitos”, eu esperava 50% ou 80%, mas, pelo link, era 13–15%
  • Ruby 3.3 parece ser uma das versões mais importantes e ricas em recursos do Ruby na última década. Eu não esperava que ele lançasse um JIT pronto para produção antes do Python, e ainda há Prism, Lrama e IRB
    Mas o que não está sendo tratado o suficiente são Ractor, o agendador de threads M:N, Fiber e Async. Especialmente no contexto do Rails, gostaria de ouvir opiniões sobre se alguém está usando esses recursos em produção

    • Era bastante previsível que o Ruby lançasse um JIT pronto para produção antes do Python. Isso porque o Ruby não tinha uma enorme comunidade de computação científica dependente de cada detalhe de implementação do interpretador hospedeiro
    • Fico me perguntando se o Ruby 3.3 é mesmo uma versão tão importante. Não sei o que há de tão significativo nela
      Ainda assim, Ractor merece mais destaque. É um recurso enorme
    • Eu realmente não entendo por que não existe uma única fila de tarefas que cubra tanto Ruby quanto Python. Sei que, em algum momento, as pessoas começaram a trocar informações por microsserviços baseados em HTTP, mas, no fim, uma fila de tarefas simples com um formato de armazenamento compartilhado pelas duas linguagens seria uma forma melhor de conectar sistemas baseados em Ruby/Rails a stacks de machine learning
      Provavelmente existem milhares de soluções privadas e customizadas dentro de empresas, baseadas em RabbitMQ ou Redis
  • Todo ano, no Natal, como um relógio, o Ruby Lang lança uma nova versão

  • Disponível no Heroku: https://devcenter.heroku.com/changelog-items/2772

  • Parece bom. O novo IRB é um interpretador Ruby interativo com autocompletar e depuração melhores. A maior parte das mudanças do Ruby 3.3 parece resultar em melhorias nas ferramentas de desenvolvedor
    A API da linguagem se mantém, em geral, consistente com versões anteriores. Escrevi um guia de atualização para o Ruby 3.3 com observações para vários gerenciadores de versão: https://mac.install.guide/ruby/update.html
    Tenho curiosidade, mas não sei qual gerenciador de versões recomendar. Antes, eu recomendava asdf, frum e chruby

    • Não vejo grandes problemas com rbenv ou asdf. Uso ambos em ambientes local e de produção
  • Resolução de nomes, como Socket.getaddrinfo, agora pode ser interrompida, e dizem que, sempre que a resolução de nomes é necessária, um worker pthread é criado e executa getaddrinfo(3) dentro dele
    Fico curioso se runtimes de outras linguagens fazem algo parecido. Criar uma thread parece pesado demais, mas talvez na prática não seja um grande problema. Mesmo pelos benchmarks deles, o overhead é pequeno, mas não é zero
    10000.times { Addrinfo.getaddrinfo("www.ruby-lang.org";, 80) } levava 2,3 s antes do patch e 3,0 s depois; 100.times { URI.open("https://www.ruby-lang.org";).read } levava 3,36 s antes do patch e 3,40 s depois

    • Será que isso é porque todas as operações de entrada/saída da biblioteca padrão precisam oferecer suporte a async/fiber?
      Tive a impressão de que, em vez de reimplementar as mesmas operações com a “cor” async, como no Python, tudo foi movido para assíncrono por padrão, mas não sei se isso está correto
    • Imagino que fiber seja mais leve do que criar uma nova thread
  • Se você já conhece Python e NodeJS, pode se perguntar se vale a pena aprender Ruby. Ruby parece interessante, mas difícil

    • Ruby é basicamente algo próximo de um Python menos popular, porém mais elegante. É uma linguagem de uso geral sólida e é especialmente boa para tarefas como scripts de shell ou limpeza de dados
      Se você é proficiente em Node e Python, deve ser bem fácil de aprender. A desvantagem é que, se você já conhece essas linguagens, ela não vai lhe trazer algo fundamentalmente novo. A vantagem é principalmente estética: Ruby oferece e incentiva formas realmente bonitas de expressar código, e é divertido experimentar isso
    • Vejo Ruby como muito melhor do que Python ou Node para tarefas com cara de script de shell e para programação interativa e exploratória voltada a tarefas de sistema. Usá-la como um “bash melhor” ou um “Perl melhor” já vale bastante a pena
      Trabalho principalmente em bases de código TypeScript, mas frequentemente recorro a Ruby quando lido com dados de log ou texto semiestruturado, ou quando faço reescritas baseadas em regex em vários arquivos. Ruby é muito divertida, provavelmente a linguagem mais divertida entre as que usei regularmente, então isso por si só já é uma recompensa
    • Depende do que você quer obter. A parte mais interessante é que Ruby, em vários aspectos, é muito parecida com Python e, ao mesmo tempo, bastante diferente
      O maior exemplo é que Ruby realmente adora blocos. Eles estão por toda a biblioteca padrão, há muito açúcar sintático, e existem incontáveis DSLs centradas em blocos. Recursos funcionais padrão também estão há muito tempo na biblioteca padrão, permitindo escrever em estilo funcional de forma fluida e legível
      Em Python, tecnicamente quase tudo isso também é possível, mas parece muito mais estranho de escrever e ler. Python tem lambdas, mas dá a impressão de não gostar muito delas para além de usos triviais; em vez disso, funções são usadas como valores de primeira classe em todos os lugares
    • Para obter dicas de como melhorar o código enquanto aprende, é bom usar Rubocop. É um excelente linter e professor
    • Usei um pouco Ruby, mais exatamente Ruby no Rails, em 2011–2013, há pouco mais de 10 anos. Na época, ainda havia um resquício da onda do RoR, que tinha surgido em 2005 e feito muito sucesso em 2007–2009
      Pessoas mais antenadas em tecnologia já estavam migrando para desenvolvimento orientado a APIs com node.js e AngularJS, muito mais rápido do que o que era feito com RoR. Em 2013, o modo padrão do RoR ainda era monolítico, e ele parecia envelhecido por não conseguir fazer bem a transição para o novo paradigma de separação entre frontend e backend
      O motivo de eu falar tanto de um framework feito em Ruby, e não do Ruby em si, é que ainda hoje acredito que 95% do desenvolvimento em Ruby seja de aplicações Rails. Ruby ficou famoso principalmente por causa do Ruby on Rails e, se o RoR estiver em declínio, Ruby provavelmente seguirá o mesmo caminho, como Perl, até se reduzir a uma pequena comunidade entusiasta
      Olhando apenas para a linguagem em si, não vejo motivo para escolher Ruby em vez de Python ou TypeScript. Nem como linguagem nem como plataforma, Ruby parece fazer algo melhor do que concorrentes que já estão mais bem estabelecidos
  • Prism é interessante. Fico curioso se há ferramentas de análise de código Ruby que o utilizem. Eu estava procurando uma forma de analisar o código da empresa

  • Dizem que a variável de ambiente RUBY_MAX_CPU=n define no máximo N, ou seja, o número máximo de threads nativas, e que o valor padrão é 8
    Acho que o padrão deveria ser o número de núcleos lógicos, como no Tokio do Rust ou em muitos runtimes M:N

    • É uma otimização que pode ser adicionada depois e tem algumas sutilezas. Pelo que me lembro, Go também foi parecido por alguns anos, e lembro de definir GO_MAX_PROCS em init() ou main()
    • Não parece certo impor um limite rígido ao número máximo de CPUs. Talvez bastasse depender do número de núcleos disponíveis
  • No Ruby 4.0, gostaria que fosse permitido um import explícito em vez da forma atual, implícita, de trazer gems para o namespace global

    • Talvez você se interesse pelo Im, de Chris Salzberg. Ele já pode ser usado no Ruby 3.2: https://github.com/shioyama/im
      Também há uma discussão sobre o recurso ainda especulativo “namespace on read”: https://bugs.ruby-lang.org/issues/19744
    • Acho que o namespace global é aceitável, seja implícito ou explícito. Em teoria, é estranho, mas na prática raramente causa problemas graças a convenções e normas sociais
      O fato de o namespace global suportar exatamente uma versão de cada gem também incentiva uma cultura saudável que valoriza ABI estável e períodos de depreciação. Comparado a certos ecossistemas de linguagem, é um ambiente dos sonhos
    • Acho que isso não é do Ruby, mas sim do Rails. Sei que, na maioria dos projetos, essa diferença praticamente não existe, mas pode ser uma decisão da equipe do Rails e não ter relação com o que a equipe do Ruby faz
      Ou talvez eu esteja dizendo algo completamente errado
    • Ruby 4.0 dificilmente aparecerá antes de 2030
      https://youtu.be/4MM5b2F9zrM?si=UT3aUbD6p_uBZehS&t=2347