Performance e otimizaçãoLink para este cabeçalho

Este documento fornece uma visão geral das técnicas e ferramentas que podem ajudá-lo a rodar o seu código Django com maior eficiência - mais rápido, e usando menos recursos do sistema.

IntroduçãoLink para este cabeçalho

Geralmente a primeira preocupação que surge é escrever código que funcione, no qual a lógica trabalhe de acordo com o que foi definido para produzir a saída esperada. Algumas vezes, entretanto, isso não será o suficiente para fazer o código funcionar de modo tão eficiente quanto seria o desejado.

Nesse caso, é preciso algo - e na prática, geralmente uma porção de coisas - para melhorar a performance do código sem, ou ao menos minimamente, afetar o seu comportamento.

Abordagens ComunsLink para este cabeçalho

O que exatamente você está otimizando?Link para este cabeçalho

É importante ter uma ideia clara do que você entende por ‘performance’. Não existe uma métrica única para ela.

Melhorar a velocidade pode ser o objetivo mais óbvio para um programa, mas algumas vezes outras melhorias de performance podem ser desejadas, tais como menor consumo de memória ou menor consumo de recursos de banda da rede ou do banco de dados.

Melhorias em uma área geralmente irão proporcionar melhor performance em outras, mas nem sempre; algumas vezes uma pode vir em detrimento das outras. Por exemplo, uma melhoria na velocidade de execução de um programa pode fazê-lo usar mais memória. Até pior, ela pode ser contraproducente - Se a melhoria na velocidade de execução consumir tanta memória ao ponto de o sistema começa a ficar sem ela, você terá causado mais mal que bem.

Existem outras escolhas para ter em mente. O seu próprio tempo é um recurso valioso, mais precioso do que o tempo de CPU. Algumas melhorias podem ser muito difíceis para valer a pena sua implementação, ou podem afetar a portabilidade ou manutenibilidade do seu código. Nem todas as melhorias de performance valem o seu esforço.

Portanto, você precisa saber quais melhorias de performance você está querendo obter, e você também precisa ter uma boa razão para caminhar nessa direção - e para tanto você precisa:

Performance benchmarkingLink para este cabeçalho

Não é bom assumir ou simplesmente chutar os locais de ineficiência do seu código.

Ferramentas do DjangoLink para este cabeçalho

django-debug-toolbar is a very handy tool that provides insights into what your code is doing and how much time it spends doing it. In particular it can show you all the SQL queries your page is generating, and how long each one has taken.

Painéis de terceiros também estão disponíveis para a barra de ferramentas, que pode (por exemplo) emitir relatórios sobre a performance do cache e tempos de renderização dos templates.

Serviços de terceirosLink para este cabeçalho

Existem vários serviços gratuitos que podem analisar e emitir relatórios de performance das páginas do seu site sob a perspectiva de um cliente remoto HTTP, simulando assim a experiência de um usuário de verdade.

These can’t report on the internals of your code, but can provide a useful insight into your site’s overall performance, including aspects that can’t be adequately measured from within Django environment.

Existem também vários outros serviços pagos que fazem uma análise similar, incluindo alguns capazes de identificar o Django e que podem se integrar com o seu código para diagnosticar sua performance de forma bem mais abrangente.

Get things right from the startLink para este cabeçalho

Some work in optimization involves tackling performance shortcomings, but some of the work can be built-in to what you’d do anyway, as part of the good practices you should adopt even before you start thinking about improving performance.

A esse respeito Python é uma excelente linguagem para se trabalhar, porque soluções que parecem elegantes e mais adequadas geralmente são também as com melhor performance. Como em muitos trabalhos, aprender o que parece correto leva tempo, mas uma das regras mais úteis é:

Work at the appropriate levelLink para este cabeçalho

O Django oferece muitas formas diferentes de se resolver um problema, mas só porque é possível fazer algo de uma certa maneira não significa que ela seja a maneira apropriada para resolvê-lo. Por exemplo, você pode acabar descobrindo que é possível calcular a mesma coisa - o número de itens em uma coleção, talvez - em um QuerySet, em Python, ou em um template.

Porém, quase sempre será mais rápido fazer isso em leveis mais baixos do que em leveis mais altos. Em leveis mais altos o sistema tem que lidar com objetos através de múltiplos níveis de abstração e maquinário.

Isto é, o banco de dados tipicamente faz coisas mais rápido do que o Python consegue fazer, que por sua vez pode fazê-las mais rápido do que a linguagem de templates.

Code
# QuerySet operation on the database
# fast, because that's what databases are good at
my_bicycles.count()

# counting Python objects
# slower, because it requires a database query anyway, and processing
# of the Python objects
len(my_bicycles)
Django template
<!--
Django template filter
slower still, because it will have to count them in Python anyway,
and because of template language overheads
-->
{{ my_bicycles|length }}

De modo geral, o level mais apropriado para o trabalho é o level mais baixo que alguém está disposto a programar.

“Caching” – cacheandoLink para este cabeçalho

Com frequência ele é custoso (isto é, lento e faminto por recursos) para calcular o valor, então podem existir grandes benefícios em salvá-lo em um cache acessível rapidamente, pronto para a próxima vez em que ele for solicitado.

É uma técnica suficientemente poderosa e significante que o Django inclui em um vasto framework para caches, assim como outras pequenas peças de funcionalidades envolvendo caches.

O framework de “cache” do DjangoLink para este cabeçalho

O framework de “cache” do Django oferece oportunidades muito significativas de ganhos de performance, salvando conteúdo dinâmico de modo que ele não precise ser calculado a cada requisição.

Para conveniência, Django oferece diferentes níveis de granularidade de cache: você pode fazer cache da saída de views específicas, ou somente de partes difíceis de se produzir, ou mesmo de um site inteiro.

Implementing caching should not be regarded as an alternative to improving code that’s performing poorly because it has been written badly. It’s one of the final steps toward producing well-performing code, not a shortcut.

O decorator cached_propertyLink para este cabeçalho

É comum ter que chamar um método de instância de uma classe mais de uma vez. Se essa função for custosa, fazer isso pode ser um desperdício.

Usando o decorator cached_property o valor retornado é salvo por uma property; a próxima vez que a função é chamada nessa instância, ela irá retornar o valor salvo ao invés de calculá-lo novamente. Repare que isso só funciona em métodos que recebem self como seu argumento e que ele muda o método para um property.

Certos componentes Django também tem sua própria funcionalidade de cache, esses são discutidos abaixo nas seções relacionadas a eles.

Entendendo lazinessLink para este cabeçalho

Laziness, ou “preguiça” em português, é uma estratégia complementar ao “caching”. Fazer cache evita reprocessamento através do armazenamento dos resultados; laziness posterga o processamento até que ele seja efetivamente solicitado.

Laziness nos permite referenciar coisas antes delas serem instanciadas, ou até mesmo antes de ser possível instanciá-las. Isso pode ser usado de várias formas.

Por exemplo, traduções “lazy” podem ser usadas antes da linguagem alvo se quer ser conhecida, isso porque ela não é usada até que a string a ser traduzida seja efetivamente requerida, como em um template renderizado.

Laziness é também uma forma de salvar recursos através da tentativa de evitar o trabalho desde o início. Isto é, um aspecto do laziness é não fazer nada até que algo realmente tenha que ser feito, porque pode acontecer de o trabalho não ser necessário. Laziness pode, portanto, ter implicações na performance, e quanto mais custoso for o trabalho, maior o potencial de ganho pelo seu uso.

Python provides a number of tools for lazy evaluation, particularly through the generator and generator expression constructs. It’s worth reading up on laziness in Python to discover opportunities for making use of lazy patterns in your code.

Laziness no DjangoLink para este cabeçalho

Django is itself quite lazy. A good example of this can be found in the evaluation of a QuerySet. QuerySets are lazy. Thus a QuerySet can be created, passed around and combined with other QuerySet instances, without actually incurring any trips to the database to fetch the items it describes. What gets passed around is the QuerySet object, not the collection of items that - eventually - will be required from the database.

Por outro lado, certas operações irão forçar a análise do QuerySet. Evitar a análise prematura de um QuerySet pode salvá-lo de fazer uma desnecessária e custosa viagem até o banco de dados.

O Django também fornece um decorator keep_lazy(). Isso permite que uma função chamada com um argumento lazy se comporte de modo lazy, somente sendo analisada quando for realmente necessário. Assim o argumento lazy - que pode ser um argumento custoso - não será chamado para análise a não ser que isso seja estritamente solicitado.

Banco de DadosLink para este cabeçalho

Otimização de banco de dadosLink para este cabeçalho

Django’s database layer provides various ways to help developers get the best performance from their databases. The database optimization documentation gathers together links to the relevant documentation and adds various tips that outline the steps to take when attempting to optimize your database usage.

Performance HTTPLink para este cabeçalho

MiddlewareLink para este cabeçalho

O Django já vem com alguns componentes de middleware úteis que podem ajudar a otimizar a performance do seu site . Eles incluem:

ConditionalGetMiddlewareLink para este cabeçalho

Adds support for modern browsers to conditionally GET responses based on the ETag and Last-Modified headers. It also calculates and sets an ETag if needed.

GZipMiddlewareLink para este cabeçalho

Comprime as respostas para todos os browsers modernos, salvando banda e tempo de transferência. Tenha em mente que atualmente o GZipMiddleware é considerado um risco de segurança, e é vulnerável a ataques que anulam a proteção fornecida pelo TLS/SSL. Veja o warning na classe GZipMiddleware para mais informações.

SessõesLink para este cabeçalho

Using cached sessionsLink para este cabeçalho

Usar sessões “cacheadas” pode ser uma forma de melhorar a performance ao eliminar a necessidade de carregar dados de sessão de uma fonte de dados mais lenta como um banco de dados e, ao invés disso, armazenar os dados de sessão mais frequentemente usados em memória.

Arquivos estáticosLink para este cabeçalho

Arquivos estáticos, que por definição não são dinâmicos, são um excelente alvo para ganhos de otimização.

ManifestStaticFilesStorageLink para este cabeçalho

Tomando vantagem das habilidades de cache dos browsers web, você pode eliminar totalmente o uso de banda para um dado arquivo depois de seu download inicial.

ManifestStaticFilesStorage appends a content-dependent tag to the filenames of static files to make it safe for browsers to cache them long-term without missing future changes - when a file changes, so will the tag, so browsers will reload the asset automatically.

“Minification”Link para este cabeçalho

Várias ferramentas e pacotes Django desenvolvidos por terceiros fornecem a habilidade de “minificar” HTML, CSS, e JavaScript. Eles removem espaços em branco desnecessários, quebras de linhas e encurtam nomes de variáveis, e assim reduzem o tamanho dos documentos que o seu site publica.

Performance nos TemplatesLink para este cabeçalho

Tenha em mente que:

  • usar {% block %} é mais rápido do que usar {% include %}

  • Templates muito fragmentados, construídos de várias pequenas peças, podem afetar a performance.

A classe cached template loaderLink para este cabeçalho

Ativar a classe cached template loader geralmente aumenta a performance drasticamente, já que ela evita compilar cada template novamente sempre que ele tiver que ser renderizado.

Utilizando versões diferentes do mesmo software disponívelLink para este cabeçalho

Às vezes é bom verificar se versões diferentes e com melhor performance do software que você utiliza estão disponíveis.

Estas técnicas são para os usuários mais avançados que querem expandir as fronteiras de performance de um site Django já bem otimizado.

Entretanto, elas não são soluções mágicas para problemas de performance, e elas provavelmente trarão pouco ou nenhum ganho para sites que já não façam as coisas mais básicas do jeito correto.

Novo é geralmente - mas nem sempre - melhorLink para este cabeçalho

It’s fairly rare for a new release of well-maintained software to be less efficient, but the maintainers can’t anticipate every possible use-case - so while being aware that newer versions are likely to perform better, don’t assume that they always will.

Isso é o que tem acontecido no Django em si. Sucessivas novas releases têm oferecido um número de melhorias em todo o sistema, mas você ainda deverá verificar a performance de sua aplicação no mundo real, pois em alguns casos você pode acabar descobrindo que mudanças significam um pior desempenho ao invés do contrário.

Novas versões do Python, e também de suas bibliotecas, também irão com frequência possuir um melhor desempenho - mas meça, ao invés de assumir isso.

Alternativas a linguagem de templates do DjangoLink para este cabeçalho

Para praticamente todos os casos, a linguagem de templates embutida no Django é perfeitamente adequada. Porém, se o gargalo no seu projeto Django parecer ser o sistema de template e você tiver exaurido outras oportunidades de remediar isso, uma alternativa de terceiros pode ser a resposta.

Jinja2 can offer performance improvements, particularly when it comes to speed.

Sistemas de template alternativos variam no quanto eles usam da linguagem de template do Django.

Implementações de softwares alternativosLink para este cabeçalho

Pode ser útil checar se o software Python que você está usando foi fornecido em uma implementação diferente que pode executar o mesmo código mais rápido.

Entretanto: a maioria dos problemas de performance em sites Django bem escritos não estão no nível de execução Python, mas sim em consultas ineficientes ao banco de dados, caches e templates. Se você estiver se apoiando em código Python mal escrito, seus problemas de performance provavelmente não serão resolvidos ao serem executados mais rápido.

Usar uma implementação alternativa pode introduzir problemas de compatibilidade, implantação, portabilidade, ou manutenção. Nem é preciso dizer que antes de adotar uma implementação atípica você deve se certificar de que ela fornece ganhos de performance suficientes para a sua aplicação que compensem o risco em potencial.

Com essas ressalvas em mente, você deve conhecer:

PyPyLink para este cabeçalho

PyPy is an implementation of Python in Python itself (the ‘standard’ Python implementation is in C). PyPy can offer substantial performance gains, typically for heavyweight applications.

A key aim of the PyPy project is compatibility with existing Python APIs and libraries. Django is compatible with versions of PyPy corresponding to the supported Python versions, but you will need to check the compatibility of other libraries you rely on.

Implementações em C de bibliotecas PythonLink para este cabeçalho

Algumas bibliotecas Python também são implementadas em C, e podem ser muito mais velozes. Elas visam oferecer as mesmas APIs. Tenha em mente que problemas de compatibilidade e diferenças de comportamento não são desconhecidos (e nem sempre evidentes imediatamente).