3 pontos por GN⁺ 2025-12-26 | 1 comentários | Compartilhar no WhatsApp
  • O interpretador com tail-calling do CPython apresentou desempenho cerca de 15% superior ao método anterior no ambiente Windows x86-64
  • Também foi confirmado um ganho de desempenho de cerca de 5% no macOS AArch64 (XCode Clang), e no Windows são usados recursos experimentais do MSVC 2026
  • Nos benchmarks do pyperformance, a maioria dos testes mostrou aumento de velocidade, com alguns chegando a 78% de melhoria
  • A principal causa do ganho de desempenho foi analisada como sendo o reset das heurísticas de otimização do compilador e melhorias de inlining
  • No lançamento oficial do Python 3.15, isso deverá ser aplicado por padrão em builds baseadas no Visual Studio 2026

Melhoria de desempenho do interpretador com tail-calling

  • Foi medido que o interpretador com tail-calling do CPython é cerca de 15% mais rápido no Windows x86-64 do que o interpretador switch-case tradicional
    • Segundo o pyperformance, a média geométrica melhorou entre 15% e 16%
    • Alguns benchmarks tiveram ganho de velocidade de até 78%, enquanto poucos casos ficaram 60% mais lentos
  • No macOS AArch64 (XCode Clang), também foi confirmado um ganho de desempenho de cerca de 5%
  • Esses resultados são válidos sob a premissa de que não haja mudanças durante o ciclo de desenvolvimento do Python 3.15

Comparação da estrutura do interpretador

  • As implementações de interpretador em C podem ser divididas em três tipos: switch-case, computed goto e tail-call threaded
    • switch-case: trata o desvio de acordo com cada instrução
    • computed goto: extensão de GCC/Clang que salta diretamente para o endereço de desvio
    • tail-call threaded: separa cada manipulador de bytecode em uma função e faz tail call para a próxima função
  • No passado, como os compiladores C não garantiam otimização de tail call, havia risco de stack overflow
  • Os atributos __attribute__((musttail)) do Clang e [[msvc::musttail]] do MSVC agora permitem forçar tail call

Resultados do build com MSVC 2026 para Windows

  • No build do CPython usando recursos experimentais do MSVC, a maioria dos benchmarks mostrou ganho de velocidade
    • Exemplos de resultados:
      • spectralnorm: 1,48x
      • nbody: 1,35x
      • bm_django_template: 1,18x
      • xdsl: 1,14x
  • Isso foi oficialmente refletido na documentação “What’s New” do Python 3.15
    • Em builds com Visual Studio 2026 (MSVC 18), será possível usar o interpretador com tail-calling
    • Bibliotecas Python puras terão ganho de cerca de 15%, e scripts pequenos podem ficar até 40% mais rápidos

Causa do ganho de desempenho

  • O tail-calling reinicializa as heurísticas de otimização do compilador, induzindo uma geração de código mais eficiente
  • O loop tradicional do interpretador do CPython é composto por uma única função com cerca de 12.000 linhas, o que causa falhas frequentes na otimização por inlining
    • Há muitos casos em que o compilador recusa o inlining para evitar aumento do tamanho do código
  • No método com tail-calling, as funções são separadas, permitindo que funções simples sejam tratadas com inline
    • Como exemplo, funções simples como PyStackRef_CLOSE_SPECIALIZED passam a ser inline
  • O mesmo fenômeno também foi relatado em builds com PGO (otimização guiada por perfil)

Como compilar e usar

  • No momento, só é possível fazer build a partir do código-fonte
    • No ambiente Visual Studio 2026, compile com o seguinte comando
      $env:PlatformToolset = "v145"
      ./PCbuild/build.bat --tail-call-interp -c Release -p x64 --pgo
      
  • Quando o desenvolvimento do Python 3.15 estiver mais estável, está prevista a distribuição oficial de binários

1 comentários

 
GN⁺ 2025-12-26
Comentários do Hacker News
  • Compartilha o trecho de código principal que gostaria que tivesse sido incluído no post do blog
    É um exemplo que mostra a diferença na definição dos atributos musttail e preserve_none entre MSVC e Clang
    Esses atributos precisam ser colocados no declarador da função e não funcionam na posição de especificador da função
    Link para o código relacionado
    Passa a impressão de que a Microsoft só informa esse tipo de recurso não público a projetos que considera importantes
    • Eu estava enganado. [[msvc::musttail]] era de fato um atributo oficialmente documentado
      Vou atualizar o post do blog para refletir isso
      Comentário relacionado no HN
    • Levanta a dúvida: “Será que contaram porque era importante, ou porque isso beneficiava eles mesmos?”
  • Lembra do caso anterior, no Python 3.14, em que um bug do LLVM 19 levou a um ganho de desempenho incorreto sendo reportado, e espera que isso não esteja acontecendo desta vez
    Ao ler o texto, conclui que a abordagem priorizou transparência e feedback rápido, então parece aceitável
    Seria melhor ainda com validação entre compiladores ou auditoria independente, mas considera confiável graças à transparência total do autor
    • O autor relembra que o erro daquela vez acabou sendo um acidente de sorte
      Como foi divulgado cedo, Nelson encontrou o bug do Clang 19, e isso permitiu corrigir antes do lançamento oficial
      Desta vez, há mais confiança porque existem duas melhorias: lógica de dispatch e inlining
      O MSVC pode transformar um interpretador com switch-case em threaded code sob certas condições, mas o CPython é complexo demais para que essa otimização seja aplicada
      Em vez disso, a abordagem com tail call dá mais controle ao autor do código C
      Referências relacionadas: condições do threaded code no MSVC, issue sobre forceinline
    • A vantagem do novo design é depender menos dos caprichos das otimizações do compilador
      Antes, otimizações como tail duplication variavam conforme a decisão do compilador, mas agora o próprio interpretador consegue expressar diretamente a forma de código de máquina desejada
      Link para discussão anterior
  • Diz que existe uma apresentação sobre problemas anteriores com compiladores e compartilha o vídeo da EuroPython 2025
  • Está criando um app GUI para Windows em Python pela primeira vez em muito tempo
    Escolheu Python porque o ecossistema do VS é pesado demais em comparação com C#/MAUI
    Achou Tkinter incômodo, e Qt exigia curva de aprendizado alta, então está usando a combinação wxGlade + wxPython
    Só precisa de uma dependência única instalável via pip, e gosta da sensação mais Pythonic
    Fica feliz com as melhorias no runtime do Windows
    • Eu prefiro a combinação Python + Qt/PySide
      Com o QtCreator dá para montar a UI rapidamente e ligar a lógica em Python, então a velocidade de desenvolvimento é muito alta
    • Recomenda também pyfltk. No GNU/Linux funcionou bem
    • Se a GUI for importante, LINQPad também pode valer a pena considerar. Fica num meio-termo entre scripting e trabalho pesado
    • Recomenda os bindings de ImGui para Python
      Em vez do modelo retained mode de Tkinter ou Qt, usa a abordagem immediate mode, o que é especialmente útil para ferramentas internas
      projeto imgui_bundle
  • Pergunta se isso não seria um problema de otimização de baixa dificuldade, questionando por que o loop do interpretador ainda não foi totalmente otimizado
    Diz que achava que já estaria escrito em assembly para as principais ISAs
    • Pelo contrário, considera que esta atualização mostra que o loop já está extremamente otimizado
      [[msvc::musttail]] é um atributo novíssimo, adicionado no MSVC 14.50 (lançado no mês passado), e a equipe do CPython o aproveitou em poucas semanas para obter ganhos de desempenho
      Documentação do musttail no MSVC
    • Python sempre teve como objetivo simplicidade antes de velocidade
      Guido priorizou a simplicidade do código, por isso a adoção de JIT demorou, e depois surgiram tentativas como a PEP 744 (JIT Compilation)
    • Não se deve ter expectativas exageradas em relação a software open source
      Otimização em assembly é um pesadelo de manutenção, e o verdadeiro gargalo do Python é o sistema de empacotamento
    • De qualquer forma, quem se importa muito com desempenho não roda Python no Windows
  • Levanta a pergunta: “Por que o interpretador de Python é muito mais lento que o V8?”
    • JavaScript usa compilação JIT, mas o CPython não
      O PyPy é rápido graças ao JIT, mas não é compatível com extensões em C
      O modelo de threads do Python também dificulta otimizações
      Já o JS é mais simples por ser single-threaded
      Como Python pode contornar isso com extensões em C, houve menos pressão para otimizar o próprio CPython
    • A quantidade e qualidade de pessoal do Google fariam uma grande diferença
      Além disso, o CPython não pode quebrar compatibilidade por causa do vasto ecossistema de extensões em C
      Já o V8 pôde mudar livremente sua estrutura interna
    • Python é muito mais dinâmico: até acesso a atributos passa pelo protocolo descriptor
      Além disso, precisa manter uma ABI C estável, o que dificulta para um JIT analisar o código livremente
    • Python é uma linguagem muito mais dinâmica que JS, e os bindings FFI limitam mudanças internas
      Cita o caso do PyPy, que sofreu para atender essas restrições
    • O JS foi otimizado com recursos massivos porque o Google queria dominar a web, enquanto Python investiu mais recursos na evolução da linguagem
      Além disso, JS só precisa suportar JS puro, enquanto Python precisa manter o ecossistema de extensões externas, o que impõe muitas limitações de otimização
  • Comenta que o novo gráfico de benchmark é interessante e pergunta com qual ferramenta ele foi gerado
    Compartilha que já usou mitata para medir desempenho de bibliotecas JS
    PR de otimização do Immer JS
  • Conta que Matt Godbolt mencionou que um interpretador baseado em tail call se encaixa melhor no branch predictor da CPU
  • Diz que há dois erros de digitação logo na primeira frase do texto e pergunta se seriam erros intencionais para parecer que não foi escrito por IA
    • O autor responde: “Obrigado, corrigi”
    • Outro usuário brinca: “Se quiser parecer que não foi escrito por IA, é só escrever você mesmo
      E satiriza características típicas de texto gerado por IA, como parágrafos curtos, tom excessivamente positivo e pouca profundidade
  • Pergunta: “Se a equipe do Python considera tail call útil, será que o próprio linguagem também vai ganhar suporte a tail call?”