Algoritmos no eficientes - programación concurrente y paralela
Martinmgf95Monografía17 de Diciembre de 2023
4.381 Palabras (18 Páginas)71 Visitas
[pic 1][pic 2]
[pic 3]
[pic 4]
Índice general
Índice general ……………………………………………………………………………………….…1
Introducción …………………………………………………………………………………………….2
Desarrollo ………………………………………………………………………………………………..3
Conclusiones …………………………………………………………………………………………13
Introducción
En el mundo de la informática, hacer que diferentes partes de un programa trabajen juntas al mismo tiempo es esencial. Imaginemos un sistema donde varias tareas se llevan a cabo simultáneamente, como nuestras computadoras que ejecutan múltiples programas al mismo tiempo. Este concepto se llama programación concurrente.
Sin embargo, cuando múltiples partes de un programa tienen que compartir información o recursos, pueden surgir problemas. Imaginemos dos programas intentando usar la misma impresora al mismo tiempo. Aquí es donde entra en juego la exclusión mutua: es la idea de que solo una parte del programa pueda acceder a ciertos datos o recursos a la vez.
En esta monografía, nos enfocaremos en un problema interesante: “Los algoritmos no eficientes” que se usan para resolver este tipo de situaciones. Estos algoritmos, aunque parezcan simples, pueden conducir a problemas complicados que afectan el funcionamiento adecuado de los sistemas.
En las próximas secciones, vamos a explorar qué es exactamente la programación concurrente y por qué es importante. También vamos a sumergirnos en algunos algoritmos comunes y entender por qué a veces pueden no ser tan eficientes como esperamos. Al comprender estos desafíos, estaremos mejor equipados para escribir programas que funcionen sin problemas incluso cuando muchas partes estén trabajando juntas al mismo tiempo.
Desarrollo
La Programación Concurrente
La programación concurrente se refiere a la ejecución simultánea de múltiples tareas en un sistema informático. En lugar de ejecutar un solo proceso a la vez, como en la programación secuencial, la programación concurrente permite que varios procesos o hilos se ejecuten en paralelo. Esto es crucial en un mundo donde la mayoría de los sistemas modernos, desde aplicaciones web hasta sistemas operativos, deben manejar múltiples solicitudes y tareas al mismo tiempo.
Importancia de la Programación Concurrente
- Rendimiento Mejorado: La programación concurrente permite que las computadoras aprovechen al máximo su capacidad de procesamiento al realizar múltiples tareas simultáneamente. Esto lleva a una mejora significativa en el rendimiento de las aplicaciones y sistemas.
- Experiencia del Usuario: En aplicaciones como videojuegos y aplicaciones web, donde la respuesta rápida es esencial, la programación concurrente asegura que las interacciones del usuario se manejen de manera rápida y fluida, mejorando así la experiencia del usuario.
- Eficiencia de Recursos: Al permitir que varios procesos compartan recursos como memoria y CPU, la programación concurrente utiliza los recursos de manera eficiente, lo que es crucial en entornos donde la optimización es clave.
- Escalabilidad: Los sistemas concurrentes están diseñados para crecer de manera eficaz a medida que aumenta la carga de trabajo. Esto los hace ideales para aplicaciones y servicios que esperan un aumento en la demanda con el tiempo.
- Problemas del Mundo Real: Muchos problemas en el mundo real, como simulaciones, análisis de datos y cálculos complejos, requieren el procesamiento simultáneo de múltiples tareas. La programación concurrente es esencial para resolver estos problemas de manera eficiente.
- Interactividad: En aplicaciones donde la interactividad en tiempo real es fundamental, como aplicaciones de chat y transmisión de video, la programación concurrente garantiza que las actualizaciones y las respuestas del sistema sean inmediatas.
La programación concurrente es, por tanto, un pilar fundamental en la informática moderna, permitiendo que los sistemas sean más rápidos, eficientes y capaces de manejar una amplia variedad de tareas complejas. A continuacion, exploraremos algunos algoritmos que se utilizan en este contexto y cómo su implementación ineficiente puede conducir a problemas significativos.
Exploración de Algoritmos en Programación Concurrente
Ahora que comprendemos la importancia de la programación concurrente en el mundo informático moderno, es crucial explorar cómo se gestionan los procesos y recursos simultáneos. Esto nos lleva a los algoritmos de sincronización, que son esenciales para garantizar que los procesos concurrentes no interfieran entre sí de manera destructiva.
Exclusión Mutua y Su Importancia
El concepto fundamental en la programación concurrente es la exclusión mutua, que asegura que solo un proceso tenga acceso a un recurso compartido en un momento dado. Imaginemos un escenario donde dos procesos intentan modificar los mismos datos simultáneamente; esto puede resultar en inconsistencias y errores graves.
Los algoritmos de exclusión mutua son cruciales porque evitan situaciones problemáticas como interbloqueos (donde los procesos quedan atrapados esperando indefinidamente uno al otro) y condiciones de carrera (donde el resultado depende del orden de ejecución de los procesos).
Algoritmos No Eficientes: Problemas y Consecuencias
A continuación, veremos ejemplos de algoritmos no eficientes que producen problemas y consecuencias al ser mal implementados.
Ejemplo de un primer intento de algoritmo que no garantiza la exclusión mutua
El siguiente es un programa que no cumple con la exclusión mutua debido a la falta de sincronización , ya que como se vera ambos procesos ingresaran en la sección critica simultáneamente, lo cual no debería ocurrir nunca, un ejemplo implementado en Java seria:
class Proceso1 implements Runnable {
public void run() {
while (true) {
// Protocolo de entrada
while (Main.v) ; // Espera activa: verifica si la sección crítica está ocupada
Main.v = true; // Entra en la sección crítica
System.out.println("Proceso 1 entró en la sección crítica.");
// Protocolo de salida
Main.v = false; // Sale de la sección crítica
System.out.println("Proceso 1 salió de la sección crítica.");
// Sección no crítica (resto del código)
}
}
}
class Proceso2 implements Runnable {
public void run() {
while (true) {
// Protocolo de entrada
while (Main.v) ; // Espera activa: verifica si la sección crítica está ocupada
Main.v = true; // Entra en la sección crítica
System.out.println("Proceso 2 entró en la sección crítica.");
// Protocolo de salida
Main.v = false; // Sale de la sección crítica
System.out.println("Proceso 2 salió de la sección crítica.");
// Sección no crítica (resto del código)
}
}
}
public class Main {
static boolean v = false;
public static void main(String[] args) {
Thread proceso1 = new Thread(new Proceso1());
Thread proceso2 = new Thread(new Proceso2());
proceso1.start();
proceso2.start();
}
}
En este ejemplo, las clases Proceso1 y Proceso2 implementan la interfaz Runnable y contienen la lógica del protocolo de entrada y salida. La clase Main contiene el método main donde se crean las instancias de los procesos y se inician como hilos independientes
Partes del programa:
Proceso1:
Protocolo de Entrada:
a) Espera Activa: Mientras v (la variable compartida) es true (indicando que la sección crítica está ocupada), el proceso se queda en espera activa, verificando continuamente si la sección crítica está libre.
b) Cuando v se convierte en false, el proceso entra en la sección crítica.
Sección Crítica:
a) Una vez dentro de la sección crítica, el proceso ejecuta las operaciones específicas de la sección crítica. En este caso, no se especifican operaciones, pero este sería el lugar donde se realizarían las tareas que necesitan exclusión mutua.
...