Python ganhou a reputação de ser poderoso, flexível e fácil de trabalhar. Essas virtudes levaram ao seu uso em uma enorme e crescente variedade de aplicações, fluxos de trabalho e campos. Mas o design da linguagem – sua natureza interpretada, seu dinamismo em tempo de execução – significa que Python sempre foi uma ordem de magnitude mais lenta do que linguagens nativas da máquina como C ou C++.
Até ao longo dos anos, os desenvolvedores têm criado uma variedade de soluções para as limitações de velocidade do Python. Por exemplo, você poderia escrever tarefas de performance-intensiva em C e envolvê-las com o Python; muitas bibliotecas de aprendizado de máquinas fazem exatamente isso. Ou você poderia usar Cython, um projeto que lhe permite borrifar código Python com informação do tipo runtime que permite compilá-lo em C.
mas as soluções nunca são ideais. Não seria ótimo se pudéssemos simplesmente pegar um programa Python existente como está, e executá-lo dramaticamente mais rápido? É exatamente isso que PyPy permite que você faça.
PyPyPy vs. CPython
PyPyPy é um substituto para o interpretador de Python de estoque, CPython. Enquanto CPython compila Python para bytecode intermediário que é então interpretado por uma máquina virtual, PyPy utiliza a compilação just-in-time (JIT) para traduzir o código Python em linguagem de montagem máquina-nativa.
Dependente da tarefa a ser executada, os ganhos de performance podem ser dramáticos. Em média, PyPy acelera Python em cerca de 7,6 vezes, com algumas tarefas aceleradas 50 vezes ou mais. O interpretador CPython simplesmente não executa os mesmos tipos de optimizações que o PyPy, e provavelmente nunca o fará, uma vez que esse não é um dos seus objectivos de design.
A melhor parte é que pouco ou nenhum esforço é necessário por parte do programador para desbloquear os ganhos que o PyPy proporciona. Basta trocar o CPython por PyPy, e na maior parte do tempo você já está feito. Existem algumas exceções, discutidas abaixo, mas o objetivo declarado do PyPy é rodar código Python existente, não modificado e fornecer um aumento automático de velocidade.
PyPyPy atualmente suporta ambos Python 2 e Python 3, por meio de diferentes encarnações do projeto. Em outras palavras, você precisa baixar diferentes versões do Python, dependendo da versão do Python que você estará executando. O ramo Python 2 do Python já existe há muito mais tempo, mas a versão Python 3 tem sido atualizada ultimamente. Atualmente ele suporta tanto Python 3.5 (qualidade de produção) quanto Python 3.6 (qualidade beta).
Além de suportar toda a linguagem Python central, PyPy trabalha com a grande maioria das ferramentas no ecossistema Python, tais como pip
para empacotamento ou virtualenv
para ambientes virtuais. A maioria dos pacotes Python, mesmo aqueles com módulos C, devem funcionar como estão, embora haja limitações que iremos abordar abaixo.
Como PyPy funciona
PyPyPy usa técnicas de otimização encontradas em outros compiladores just-in-time para linguagens dinâmicas. Ele analisa a execução de programas Python para determinar o tipo de informação dos objetos à medida que são criados e usados em programas, depois usa essa informação como um guia para acelerar as coisas. Por exemplo, se uma função Python funciona com apenas um ou dois tipos de objetos diferentes, PyPy gera código de máquina para lidar com esses casos específicos.
As otimizações do Python são tratadas automaticamente em tempo de execução, então você geralmente não precisa ajustar sua performance. Um usuário avançado pode experimentar as opções de linha de comando do PyPy para gerar código mais rápido para casos especiais, mas só raramente isso é necessário.
PyPyPy também se afasta da forma como o CPython lida com algumas funções internas, mas tenta preservar comportamentos compatíveis. Por exemplo, PyPy trata a coleta de lixo de forma diferente do CPython. Nem todos os objetos são coletados imediatamente quando saem do escopo, então um programa Python rodando em PyPy pode mostrar uma área de memória maior do que quando rodando em CPython. Mas você ainda pode usar os controles de coleta de lixo de alto nível do Python expostos através do módulo gc
, tais como gc.enable()
, gc.disable()
, e gc.collect()
.
Se você quiser informações sobre o comportamento do JIT do PyPy em tempo de execução, PyPy inclui um módulo, pypyjit
, que expõe muitos ganchos JIT à sua aplicação Python. Se você tem uma função ou módulo que parece estar funcionando mal com o JIT, pypyjit
permite obter estatísticas detalhadas sobre ele.
Outro módulo específico do PyPy, __pypy__
, expõe outras características específicas do PyPy, então pode ser útil para escrever aplicações que aproveitam essas características. Devido ao dinamismo do Python em tempo de execução, é possível construir aplicações Python que utilizam essas características quando o PyPy está presente e as ignora quando não está.
Limitações do PyPyPy
Mágico como o PyPy pode parecer, não é mágico. PyPy tem certas limitações que reduzem ou obviam a sua eficácia para certos tipos de programas. Infelizmente, PyPy não é um substituto completamente universal para o CPython em tempo de execução.
PyPyPy funciona melhor com aplicações Python puras
PyPyPy sempre funcionou melhor com aplicações Python “puras” – ou seja, aplicações escritas em Python e nada mais. Pacotes Python que fazem interface com bibliotecas em C, como o NumPy, não se deram tão bem devido à forma como o PyPy emula as interfaces binárias nativas do CPython.
Desenvolvedores do Python se desvaneceram nesta edição, e tornaram o PyPy mais compatível com a maioria dos pacotes Python que dependem de extensões em C. Numpy, por exemplo, funciona muito bem com PyPy agora. Mas se você quer compatibilidade máxima com extensões C, use CPython.
PyPyPy funciona melhor com programas mais longos
Um dos efeitos colaterais de como o PyPy otimiza os programas Python é que os programas mais longos se beneficiam mais de suas otimizações. Quanto mais tempo o programa for executado, mais informação do tipo run-time o PyPy pode reunir, e mais otimizações ele pode fazer. Scripts Python únicos não se beneficiarão deste tipo de coisa. As aplicações que se beneficiam tipicamente têm loops que rodam por longos períodos de tempo, ou rodam continuamente em background-web frameworks, por exemplo.
PyPyPy não faz compilação antecipada
PyPy compila código Python, mas não é um compilador para código Python. Devido à forma como PyPy executa as suas optimizações e ao dinamismo inerente ao Python, não há forma de emitir o código JIT resultante como um binário autónomo e reutilizá-lo. Cada programa tem de ser compilado para cada execução. Se você quiser compilar Python em código mais rápido que possa ser executado como uma aplicação autônoma, use Cython, Numba, ou o projeto Nuitka atualmente experimental.