Saltar al contenido

Domina Python: Proyectos Prácticos de Procesos, Concurrencia y APIs

Descubre una guía paso a paso en la que aprenderás a crear herramientas útiles en Python. Desde la monitorización y gestión de procesos del sistema, pasando por la implementación de hilos para gestionar usuarios y sesiones, hasta la simulación de pedidos en un entorno de comercio electrónico y la integración con APIs REST. ¡Una lectura imprescindible para potenciar tus habilidades de programación!


1. Control y Supervisión de Procesos en el Sistema

En este primer apartado veremos cómo crear una utilidad en Python que nos permita listar los procesos activos del sistema, identificar uno en particular (por ejemplo, el Bloc de notas) y, además, poder finalizar un proceso seleccionado por el usuario. Se hace uso de la librería psutil para interactuar con el sistema.

Paso a paso:

  1. Listado de Procesos
    Recorremos los procesos activos e imprimimos su nombre y PID. Si se detecta el Bloc de notas (usualmente “Notepad.exe”), se mostrará un mensaje especial.
  2. Finalización de un Proceso
    Se solicita al usuario que ingrese el identificador (PID) del proceso que desea terminar. El programa intenta finalizarlo y, en caso de error (como falta de permisos), se informa adecuadamente.
  3. (Opcional) Información Adicional
    Se puede extender la funcionalidad para mostrar detalles como el uso de CPU y memoria.

A continuación, se muestra un ejemplo de código:

import psutil
import time

def mostrar_procesos():
    print("\n--- Lista de Procesos Activos ---")
    for proceso in psutil.process_iter(['pid', 'name', 'cpu_percent', 'memory_info']):
        try:
            info = proceso.info
            pid = info.get('pid')
            nombre = info.get('name')
            # Mensaje especial para Notepad
            if nombre and "Notepad.exe" in nombre:
                print(f"{nombre} (PID: {pid}) --> ¡El Bloc de notas está en ejecución!")
            else:
                print(f"{nombre} (PID: {pid})")
        except psutil.NoSuchProcess:
            continue

def terminar_proceso():
    try:
        pid_input = int(input("\nIngrese el PID del proceso que desea finalizar (o 0 para salir): "))
        if pid_input == 0:
            return False
        proceso = psutil.Process(pid_input)
        proceso.terminate()
        proceso.wait(timeout=3)
        print(f"Proceso con PID {pid_input} finalizado correctamente.")
    except psutil.NoSuchProcess:
        print("Error: No se encontró el proceso.")
    except Exception as error:
        print(f"Error al intentar finalizar el proceso: {error}")
    return True

def main():
    while True:
        mostrar_procesos()
        if not terminar_proceso():
            print("Saliendo del programa de gestión de procesos...")
            break
        time.sleep(1)  # Pausa breve para actualizar la lista

if __name__ == "__main__":
    main()

Nota: Asegúrate de ejecutar este script con los permisos necesarios, ya que terminar ciertos procesos podría requerir privilegios elevados.


2. Gestión Concurrente de Datos de Usuarios con Hilos

Esta sección aborda cómo trabajar con hilos (threads) para procesar la información de varios usuarios. Usaremos tanto args como kwargs para pasar parámetros a cada hilo, permitiendo una gestión personalizada de la información.

Detalles de la implementación:

  1. Función de Procesamiento
    Se define una función que recibe un identificador de usuario mediante args y detalles como nombre y edad mediante kwargs. La función muestra estos datos.
  2. Creación y Lanzamiento de Hilos
    Se crea una lista de usuarios y, para cada uno, se inicia un hilo que ejecuta la función de procesamiento. Se incluye una pausa aleatoria para simular el tiempo de procesamiento y observar la concurrencia.
  3. Sincronización
    Se espera a que todos los hilos finalicen antes de continuar.

Ejemplo de código:

import threading
import time
import random

def procesar_usuario(id_usuario, **datos):
    # Simulación de tiempo de procesamiento aleatorio
    time.sleep(random.uniform(0.5, 2))
    nombre = datos.get('nombre', 'Desconocido')
    edad = datos.get('edad', 'N/A')
    print(f"Usuario ID: {id_usuario}, Nombre: {nombre}, Edad: {edad}")

def main():
    # Lista de usuarios: (ID, nombre, edad)
    usuarios = [
        (1, 'Ana', 30),
        (2, 'Carlos', 22),
        (3, 'Beatriz', 27),
        (4, 'David', 35),
        (5, 'Elena', 29)
    ]
    
    hilos = []
    for usuario in usuarios:
        id_usuario, nombre, edad = usuario
        hilo = threading.Thread(target=procesar_usuario, args=(id_usuario,), kwargs={'nombre': nombre, 'edad': edad})
        hilos.append(hilo)
        hilo.start()
    
    # Esperar a que todos los hilos finalicen
    for hilo in hilos:
        hilo.join()
    
    print("Todos los usuarios han sido procesados.")

if __name__ == "__main__":
    main()

3. Manejo de Sesiones de Usuario en Entornos Multihilo

En este ejemplo, simulamos la gestión de sesiones en un entorno donde múltiples hilos trabajan de forma simultánea. Se utiliza threading.local() para garantizar que cada hilo almacene su propia información de sesión, evitando interferencias.

¿Cómo lo implementamos?

  1. Definición de la Clase de Sesión
    Creamos una clase que tenga métodos para iniciar y mostrar la sesión del usuario.
  2. Uso de threading.local()
    Utilizamos un objeto local a los hilos para almacenar la instancia de sesión correspondiente a cada hilo.
  3. Ejecución Concurrente
    Se lanzan varios hilos, cada uno iniciando sesión con un nombre distinto, asegurando que la información sea exclusiva para cada uno.

Ejemplo de código:

import threading
import time

class SesionUsuario:
    def iniciar_sesion(self, nombre_usuario):
        self.nombre = nombre_usuario
    
    def mostrar_sesion(self):
        print(f"Sesión iniciada para el usuario: {self.nombre}")

# Objeto local para cada hilo
datos_sesion = threading.local()

def gestionar_sesion(nombre_usuario):
    # Cada hilo crea su propia instancia de sesión
    datos_sesion.sesion = SesionUsuario()
    datos_sesion.sesion.iniciar_sesion(nombre_usuario)
    # Simular algún tiempo de procesamiento
    time.sleep(1)
    datos_sesion.sesion.mostrar_sesion()

def main():
    nombres = ['Ana', 'Carlos', 'Beatriz', 'David', 'Elena']
    hilos = []
    for nombre in nombres:
        hilo = threading.Thread(target=gestionar_sesion, args=(nombre,))
        hilos.append(hilo)
        hilo.start()
    
    for hilo in hilos:
        hilo.join()
    
    print("Todas las sesiones han sido gestionadas.")

if __name__ == "__main__":
    main()

4. Simulación de Pedidos en un Comercio Electrónico con el Patrón Productor-Consumidor

Este proyecto simula el proceso en el que clientes generan pedidos (productores) y empleados los procesan (consumidores). La comunicación se gestiona mediante una cola compartida, garantizando que:

  • Los clientes esperen si la cola está llena.
  • Los empleados se bloqueen si la cola se encuentra vacía.

Puntos clave de la implementación:

  1. Configuración de la Cola
    Se utiliza queue.Queue con una capacidad máxima definida para controlar el flujo de pedidos.
  2. Funciones de Cliente y Empleado
    • Clientes: Generan pedidos con un identificador único y los colocan en la cola, simulando demoras aleatorias.
    • Empleados: Extraen pedidos de la cola y los procesan, también con tiempos de espera simulados.
  3. Control del Número Total de Pedidos
    La simulación se detiene una vez que se han generado y procesado 15 pedidos en total.

Ejemplo de código:

import threading
import time
import random
from queue import Queue

# Cola compartida con capacidad máxima de 5 pedidos
cola_pedidos = Queue(maxsize=5)
# Variables globales para controlar la simulación
total_pedidos = 0
total_procesados = 0
max_pedidos = 15
lock = threading.Lock()

def cliente(id_cliente):
    global total_pedidos
    while True:
        with lock:
            if total_pedidos >= max_pedidos:
                break
            total_pedidos += 1
            pedido = f"Pedido-{total_pedidos}"
        # Esperar si la cola está llena
        cola_pedidos.put(pedido)
        print(f"Cliente {id_cliente}: Generó {pedido}")
        time.sleep(random.uniform(1, 2))

def empleado(id_empleado):
    global total_procesados
    while True:
        with lock:
            if total_procesados >= max_pedidos:
                break
        try:
            # Esperar a que haya un pedido en la cola
            pedido = cola_pedidos.get(timeout=3)
            print(f"Empleado {id_empleado}: Procesó {pedido}")
            cola_pedidos.task_done()
            time.sleep(random.uniform(2, 3))
            with lock:
                total_procesados += 1
        except:
            # Timeout o cola vacía
            continue

def main():
    # Crear 3 hilos de clientes
    clientes = [threading.Thread(target=cliente, args=(i,)) for i in range(1, 4)]
    # Crear 2 hilos de empleados
    empleados = [threading.Thread(target=empleado, args=(i,)) for i in range(1, 3)]
    
    for c in clientes:
        c.start()
    for e in empleados:
        e.start()
    
    for c in clientes:
        c.join()
    for e in empleados:
        e.join()
    
    print("Todos los pedidos han sido procesados.")

if __name__ == "__main__":
    main()

Consejo: La sincronización mediante lock es fundamental para evitar condiciones de carrera al actualizar las variables compartidas.


5. Conexión y Consumo de una API REST con Python

El último proyecto consiste en interactuar con una API pública para extraer y mostrar información de interés. En este ejemplo, se usará la API de OpenWeatherMap, pero puedes adaptar el código a cualquier otra API.

Pasos a seguir:

  1. Realizar la Solicitud HTTP
    Utilizamos la librería requests para enviar una petición GET a la API.
  2. Procesar la Respuesta en Formato JSON
    Se extraen datos específicos, como la temperatura, la descripción del clima y el nombre de la ciudad.
  3. Manejo de Errores
    Se verifica el código de estado y la existencia de los datos antes de mostrarlos, para asegurar la robustez del programa.

Ejemplo de código:

import requests

def obtener_clima(ciudad, api_key):
    url = f"http://api.openweathermap.org/data/2.5/weather?q={ciudad}&appid={api_key}&units=metric&lang=es"
    try:
        respuesta = requests.get(url)
        if respuesta.status_code == 200:
            datos = respuesta.json()
            # Verificar que las claves necesarias estén en la respuesta
            if "main" in datos and "weather" in datos:
                temperatura = datos["main"].get("temp")
                descripcion = datos["weather"][0].get("description")
                print(f"Ciudad: {ciudad}")
                print(f"Temperatura: {temperatura}°C")
                print(f"Clima: {descripcion}")
            else:
                print("La respuesta no contiene la información esperada.")
        else:
            print(f"Error en la solicitud: Código de estado {respuesta.status_code}")
    except Exception as error:
        print(f"Ocurrió un error al conectar con la API: {error}")

def main():
    # Reemplaza 'TU_API_KEY' con tu clave de OpenWeatherMap
    api_key = 'TU_API_KEY'
    ciudad = input("Ingrese el nombre de la ciudad: ")
    obtener_clima(ciudad, api_key)

if __name__ == "__main__":
    main()

Recomendación: Regístrate en OpenWeatherMap para obtener una API Key gratuita. Recuerda manejar adecuadamente posibles excepciones o respuestas inesperadas.


Conclusión

Estos proyectos demuestran cómo, con Python, se pueden abordar diferentes desafíos prácticos:

  • Monitoreo y gestión de procesos para controlar y finalizar aplicaciones en ejecución.
  • Uso de hilos para procesar información de múltiples usuarios y gestionar sesiones de forma aislada.
  • Simulación de sistemas concurrentes mediante el patrón productor-consumidor, útil en aplicaciones de comercio electrónico.
  • Interacción con APIs REST para integrar datos externos en nuestras aplicaciones.

Cada ejemplo se ha explicado paso a paso, de forma que puedas adaptar y expandir estas soluciones a tus propios proyectos. ¡Experimenta, modifica el código y sigue aprendiendo!

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Información básica sobre protección de datos Ver más

  • Responsable: Tomas Gonzalez.
  • Finalidad:  Moderar los comentarios.
  • Legitimación:  Por consentimiento del interesado.
  • Destinatarios y encargados de tratamiento:  No se ceden o comunican datos a terceros para prestar este servicio.
  • Derechos: Acceder, rectificar y suprimir los datos.
  • Información Adicional: Puede consultar la información detallada en la Política de Privacidad.

error: Content is protected !!

Descubre más desde Tomás González: Formador y Desarrollador Web

Suscríbete ahora para seguir leyendo y obtener acceso al archivo completo.

Seguir leyendo

Este sitio web utiliza cookies, si necesitas más información puedes visitar nuestra política de privacidad    Ver
Privacidad