Thursday, May 5, 2022

La importancia de la buena administración de ambientes virtuales en Python

 Introducción

Cuando alguien se inicia en la programación con Python, posiblemente no conozca el concepto de ambientes virtuales y sus implicaciones en la dependencia de paquetes, como en el uso de memoria del recurso de hardware que utilice. Este blog permitirá al lector conocer un poco sobre estos ambientes virtuales y crear un criterio para saber cuándo usarlos en sus diferentes proyectos.
Un ambiente virtual es una herramienta que ayuda a preservar las dependencias requeridas por diferentes proyectos separadas, creando ambientes virtuales aislados entre ellos. Representa una herramienta muy importante para los programadores en Python. 

Los ambientes virtuales son necesarios porque:[1]

  • Eliminan problemas de dependencia de paquetes, al dar la posibilidad de instalar versiones funcionales de éstos a versiones de Python; por ejemplo, Pytorch funciona muy bien para Python3.8 pero no para otras, específicamente con arquitecturas de hardware aarch64[2] .
  • Hace que el proyecto esté auto contenido y sea reproducible, capturando el listado de todos los paquetes en un archivo conocido como requirements.txt. Generalmente, almacena en una carpeta todos esos paquetes.
  • Permite instalar los paquetes en un anfitrión sin tener los privilegios para ello.
  • Mantiene la carpeta global “site-packages/” limpia, removiendo la necesidad de instalar paquetes con alcance a todo el sistema y que posiblemente, solo sean necesarios para un proyecto.
  • Pueden ser importados y exportados para ser reutilizados en varias computadoras.

Existen dos herramientas para crear ambientes virtuales, tanto en windows como en linux: Venv y Virtualenv.

Tabla 1. Código a ejecutar para lograr diferentes acciones entre venv y virtualenv.

Aunque son muy parecidos en la aplicación, Vritualenv se caracteriza de Venv por:[6]

  • Es más lento (al no tener el método de inicialización de datos de la aplicación).
  • No es tan extensible.
  • No puede crear entornos virtuales para versiones de python instaladas arbitrariamente (y descubrirlas automáticamente).
  • No se puede actualizar a través de pip.
  • No tiene una API programática tan rica (describe entornos virtuales sin crearlos).

De forma adicional, venv no puede descubrir automáticamente versiones de python instaladas arbitrariamente, mientras que virtualenv sí lo hace. Esto significa que con venv debe especificar la ruta completa del ejecutable de python, si desea usar alguna otra versión de python que no sea la primera en la ruta[7]. Con virtualenv, solo puede dar el número de versión. Consulte el descubrimiento de python en la documentación de virtualenv.

En tema de espacio sí debe considerarse crear la menor cantidad de ambientes virtuales. Generalmente, el programador utiliza un IDE[8] para redactar, depurar y ejecutar sus programas, uno de ellos bastante utilizado es PyCharm[9] que resulta gratuito para programar en Python y es multiplataforma.

Cada vez que se redacta el código para un proyecto, se abre una ventana como la mostrada en la figura 1, donde se aprecian los siguientes campos:

  • Location (El primer campo). La ubicación de los archivos de código y auxiliares que componen el proyecto.
  • Location (Abajo de new environment). La ubicación de los paquetes para el ambiente virtual a crear.
  • Base interpreter.  La ubicación del ejecutable Python con su versión específica a utilizar
Fig.1 Ventana de configuración para un proyecto nuevo en PyCharm.

En tal caso se recomienda tener una versión preferida de Python, la cual puede instalarse de manera global para todo el sistema y, en tal caso, se podrán seleccionar las opciones “Inherit global site-packages” y “make avaiblable for all projects”, lo cual ocasionará que cada proyecto tenga un conjunto de paquetes comunes, ahorrando memoria del anfitrión.
Si no se tiene una versión preferida, entonces no deberán seleccionarse las opciones mencionadas en el párrafo anterior, pero deberá tomarse en cuenta que cada versión instalará sus propios paquetes y utilizará un espacio de memoria aislado de otras versiones.

La figura 2 Muestra el caso en que se crean ambientes virtuales para almacenar paquetes propios de la aplicación. El uso de memoria en disco duro es considerable, siendo el mayor de 4.3GB y el menor de 154MB. Si se almacenaran en los ambientes virtuales los códigos de tipo py, la cantidad de memoria utilizada por todos los proyectos en la carpeta “PyCharmProjects” podría reducirse hasta llegar cercanamente a un 33%; es decir, al proyecto que más memoria requiere.

Fig.2 Carpetas que contienen ambientes virtuales para proyectos en Python.

Conclusiones

Los ambientes virtuales en Python se utilizan para aislar los recursos que requieren diferentes versiones de Python, lo cual facilita al programador la redacción de diversor programas asegurando la compatibilidad con los paquetes utilizados.
Se recomienda utilizar una versión de Python global para el sistema para disponer de todos los paquetes a utilizar en la mayoría de proyectos y crear la menor cantidad de ambientes virtuales que utilice paquetes distintos a la versión global, porque de esta manera se utilizará de manera óptima, los recursos de memoria del anfitrión.

Preguntas motivadoras

  • ¿Cuál piensa que es el porcentaje de personas que, sabiendo programar aplicaciones sencillas de Python, desconocen la importancia de la buena administración de ambientes virtuales?
  • ¿Será necesario tener varios ambientes virtuales en un IoT?
  • ¿Cuál será la diferencia de instalar Python en un entorno Conda, respecto de los mencionados anteriormente?

Lecturas recomendadas

  • Creación y administración de ambientes en Python. [enlace]
  • Comparación de venv y virtualenv. [enlace]
  • Virtualenv and venv: Python virtual environments explained. [enlace]
  • Pipenv & Virtual Environments. [enlace]
  • Installing packages using pip and virtual environments. [enlace]

Vídeos sugeridos

  • Python Tutorial: VENV (Windows) - How to Use Virtual Environments with the Built-In venv Module. [enlace]
  • Learn Python 1: First install and Virtual Environments - Windows 10. [enlace]
  • The Complete Guide to Python Virtual Environments!. [enlace]
  • Python Tutorial: VENV (Mac & Linux) - How to Use Virtual Environments with the Built-In venv Module. [enlace]
  • How to Create Python Virtual Environment on Ubuntu – virtualenv. [enlace]
  • How to use a Python Virtual Environment the RIGHT way with Jupyter Notebook. [enlace]

Referencias

    [1] https://towardsdatascience.com/virtual-environments-104c62d48c54
    [2] https://elandroidefeliz.com/identificar-tipo-de-procesador-en-android/
    [3] https://www.collinsdictionary.com/dictionary/english/built-in-feature
    [4] https://towardsdatascience.com/virtual-environments-104c62d48c54
    [5] https://www.geeksforgeeks.org/python-virtual-environment/
    [6] https://virtualenv.pypa.io/en/latest/
    [7] [enlace]
    [8] https://www.codecademy.com/article/what-is-an-ide
    [9] https://www.jetbrains.com/pycharm/download/#section=windows





Tuesday, May 3, 2022

Aceleración de código python mediante clases

Introducción

Es de interés para todo programador, que sus códigos se ejecuten con la mayor rapidez posible. Al ejecutarse un programa rápidamente, se puede ahorrar dinero porque ya no es necesario utilizar un hardware con altas prestaciones y, además, el usuario se sentirá más cómodo al apreciar los resultados de su interacción con la computadora más rápidamente.
Python es un lenguaje interpretado, lo cual le hace lento comparado con C o C++, ya que éste último es compilado[1] y, aunque muchas de sus librerías son compiladas en C++ para que un programa se ejecute más rápidamente[2], mucho del código aún debe ser interpretado, lo cual ralentiza el programa global.

 Consejos para agilizar la ejecución de los programas

 Existen muchas publicaciones que brindan consejos para ejecutar los programas más rápidamente, entre otras, pueden mencionarse[3]:

  • Especifique tipos de datos en Python. Python utiliza un tiempo importante en detectar el tipo de variable a utilizar según el contexto en muchas ocasiones, lo cual no sucede si se declara el tipo desde el la creación de la misma.
  • Reemplace listas con expresiones generadoras. Especialmente cuando se utilizan operaciones que aglutinan un conjunto de datos; es mejor aplicar la expresión aritmética directamente a una función que a una lista de números. Este código sum([num**2 for num in range(1000000)]) tarda más que éste sum((num**2 for num in range(1000000)))
  • Reemplace variables globales con variables locales. Las variables locales se ejecutan más rápidamente, dado su contexto.
  • Evite importar librerías completas. Es mejor utilizar from A import B, ya que de esta manera se reduce el tiempo de ejecución de las funciones o métodos importados. 

En los lenguajes de programación orientados a objetos se disponen de clases y funciones. Las primeras tienen métodos que se parecen mucho a las funciones, ya que entregan un resultado después de procesar información correspondiente a sus argumentos de entrada.

La tabla 1 muestra las diferencias entre los métodos y las funciones[4].

Tabla 1. Diferencias entre métodos y funciones.

Un experto opina[5]:

“ La función proporciona su propio entorno para las variables, por lo que la metatabla cambia para adaptarse al nuevo entorno, y cuando la función finaliza, el entorno vuelve al estado de la capa exterior. En un estado ideal, una función no debería tener efectos secundarios.
La clase, por otro lado, sirve para la generación de objetos. Tras la inicialización, los objetos se crean y almacenan como tablas hash con sus respectivas direcciones. Con el tiempo, dichos objetos se eliminan de la memoria, ya sea manualmente o mediante la recolección de elementos no utilizados.”

Exposición del caso

Sin embargo, en el IIIE (Instituto de Investigación e Innovación en Electrónica) de la Universidad Don Bosco, se ha llevado un proyecto que permite comparar la ejecución entre funciones y métodos, desarrollado en una raspberry-pi utilizada para realizar el reconocimiento de rostros. Dado que un IoT tiene prestaciones limitadas, se pensó en una forma para optimizar el programa, proponiéndose utilizar clases con sus respectivos métodos para procesar la información en lugar de funciones aisladas.

La figura 1 muestra los diagramas de flujo utilizados para métodos y funciones.

Fig. 1 Diagramas de flujo: a) Usando funciones, en cada bloque indicado con (1), b) Usando métodos de clase creados al inicio del programa y usados en bloques (2)

Los resultados se muestran en la tabla siguiente, donde se tienen dos procesos principales “Espera” e “Identificación total”. Para cada uno de ellos se midió el tiempo de ejecución, siendo T1 con la aplicación de funciones y T2 con el uso de clases. En la columna “T2/T1” puede apreciarse en una notación de porcentaje, la relación de tiempos para la ejecución del código, evidenciando que el uso de clases ha reducido a 70% y 33% el tiempo de espera e identificación total, respectivamente.

Tabla 2. Comparativa en los tiempos de ejecución utilizando funciones (T1) y utilizado clases con sus respectivos métodos (T2)
 Conclusión

Utilizar clases con sus respectivos métodos para procesar la información que administra un programa, reduce el tiempo de ejecución al optimizar los recursos de hardware. Por tanto, se recomienda utilizar esta práctica en lugar de múltiples funciones independientes.

Lecturas recomendadas

  • Python Classes and Objects [Enlace]
  • Classes [Enlace]
  • Python Objects and Classes [Enlace]
  • Speed Up Python Code [Enlace]
  • Optimization Tips for Python Code [Enlace]
  • Performance tips [Enlace]
  • Optimizing Your Python Code [enlace]
  • Python Performance Tuning: 20 Simple Tips [Enlace]

Vídeos recomendados

  •  Python OOP Tutorial 1: Classes and Instances [Enlace]
  • Python Classes and Objects - OOP for Beginners [Enlace]
  • Python Classes and Objects || Python Tutorial || Learn Python Programming [Enlace]
  • Python Object Oriented Programming (OOP) - For Beginners [Enlace]

Referencias

    [1] https://www.geeksforgeeks.org/difference-between-compiled-and-interpreted-language/
    [2] https://www.pythonpool.com/precompiled-standard-library-in-python/
    [3] https://towardsdatascience.com/10-techniques-to-speed-up-python-runtime-95e213e925dc
    [4] https://techvidvan.com/tutorials/python-methods-vs-functions/
    [5] https://www.quora.com/Are-classes-slower-than-functions-in-Python