35. Python y Rendimiento#
Python es un lenguaje interpretado de alto nivel que es muy conveniente para prototipar y hacer análisis exploratorio. Sin embargo, esta conveniencia tiene un costo:
Python tiene un menor rendimiento a igual complejidad en comparación a lenguajes compilados de bajo nivel
Podemos ser más específicos y hablar de eficiencia de diversas índoles:
Eficiencia temporal: Tiempo para completar una tarea (tiempo en la CPU)
Eficiencia espacial: Utilización de espacio (memoria RAM, disco)
Ambos son factores críticos en algunas aplicaciones, por ejemplo aplicaciones con muchos datos o mucho cómputo.
Existe entonces una necesidad por mejorar el rendimiento de nuestro código. En esta serie de lecciones veremos distintas formas de optimizar código escrito en Python.
35.1. ¿Qué es la optimización de códigos/software?#
Optimización se refiere a modificar una rutina computacional para mejorar su eficiencia, es decir reducir sus tiempos de ejecución y/o consumo de recursos. El aspecto que se intenta modificar es aquel que limita nuestro programa. Un programa puede estar:
limitado en CPU: compute-bound
limitado en memoria: memory-bound
limitado en ancho de banda: bandwidth-bound
limitado en entrada/salida: I/O bound
En el ámbito de la computación científica lo más común es enfrentar programas que están límitados en CPU, es decir:
programas que utilizan la mayor parte de su tiempo haciendo cálculos
programas que mejoran su rendimiento con la velocidad del CPU
Nota
En ciertos casos podemos disminuir el tiempo de ejecución de una rutina incrementando el uso de memoria. Esto podría convertir un programa que es limitado en CPU a uno que es limitado en memoria.
35.2. Antes de optimizar#
Considera las siguientes preguntas antes de comenzar el (a veces arduo) proceso de optimizar tus códigos.
¿Cuándo optimizar?
Si:
tu rutina está incompleta o no entrega el resultado esperado
Entonces:
No es momento de optimizar
Para casi cualquier rutina que escribamos, deberíamos considerar la secuencia:
que (la rutina) corra
que (la rutina) retorne el resultado correcto
(opcionalmente) que (la rutina) tenga un buen rendimiento
Importante
La optimización está asociada al último punto y se lleva a cabo luego de cumplir los dos primeros
En la práctica hay que considerar que optimizar podría:
Hacer el código más complicado y menos legible
Introducir bugs
Tomar tiempo y bastante dedicación
Por lo tanto debemos evitar optimizar de forma prematura
La optimización prematura es la raíz de todos los males
¿Por qué optimizar?
En la secuencia mostrada anteriormente, podemos notar que el último punto no es esencial como lo son los dos primeros. Optimizar solo es necesario si nuestro código:
no entrega el resultado correcto en el tiempo requerido
requiere más memoria que la disponible en el hardware donde va a correr
¿Dónde optimizar?
Se debe evitar gastar tiempo optimizando rutinas que influyan poco en el rendimiento total del programa. La optimización debería concentrarse en las secciones más lentas y/o costosas: cuellos de botella
Previo a optimizar debemos hacer un perfilado (profiling) de nuestro código para encontrar las secciones críticas. Veremos como hacer perfilado con ipython a continuación.