# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3 (ipykernel)
#     language: python
#     name: python3
# ---

# # 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

# ## ¿Qué es la optimización de códigos/software?
#
# 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
#
#
# :::{note}
#
# 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. 
#
# :::
#  

# ## Consejos 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 
#
# Dicho de otro modo, para casi cualquier rutina que escribamos, deberíamos considerar la secuencia
#
# 1. que (la rutina) corra
# 1. que (la rutina) retorne el resultado correcto
# 1. (opcionalmente) que (la rutina) tenga un buen rendimiento
#
# :::{important}
#
# 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
#
# ```{epigraph}
# La optimización prematura es la raíz de todos los males 
#
# -- [<NAME>](http://wiki.c2.com/?PrematureOptimization)
# ```
#
# **¿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 ***profiling*** de nuestro código para encontrar las secciones críticas



StarcoderdataJupyterScriptsDedupFiltered