Procesamiento: DESCOMPOSICIÓN DE INFORMACIÓN PARALELA Periodo: Mayo – Septiembre 2022 OBJETIVO DE LA CLASE:
✔ ENTENDER SOBRE CÓMO SE PROCESA Y SE LOGRA GRAN RENDIMIENTO DE LOS
RECURSOS DE PROCESAMIENTO EN UN COMPUTADOR. CONCEPTOS BÁSICOS La necesidad de contar con una máquina que permitiera desarrollar grandes cantidades de calculo de forma repetitiva y sin equivocarse, desarrollo un mercado de fabricación de procesadores de miles de millones de dólares en el mercado internacional El CPU ha estado en continuo desarrollo mejorando la capacidad de procesamiento y disminución del tiempo para obtener un resultado Los procesadores poseen una arquitectura desarrollada para ubicar datos e instrucciones en los registros de la ALU (AX, BX, CX, DX) que las ejecuta de una en una, en una secuencia sucesiva de acciones donde cada proceso produce latencia (tiempo que se da entre la aplicación de un estímulo y la respuesta de dicho estímulo) de procesamientos, el cómputo de estas instrucciones se ha mejorado con la creación de procesadores con varios cores (núcleos)/ALU. Las aplicaciones o programas que se desarrollan en los primeros niveles de las carreras de informática no necesitan de grandes recursos de procesamiento pero en la actualidad se han incrementado las necesidades de procesamiento sobre todo en el campo de la animación gráfica y en el procesamiento de grandes volúmenes de información como los algoritmos de inteligencia artificial Por el creciente mercado de los videojuegos y la necesidad de ofrecer ambientes cada vez más reales se desarrollo una unidad de procesamiento GPU que se incorpora al computador en forma de tarjeta gráfica con característica notables en el procesamiento de imágenes con muchos detalles La GPU unidad de procesamiento gráfico, a diferencia del CPU este recurso tecnológico permite el trabajo en paralelo con la capacidad de trabajar con gran cantidad de hilos y obtención rápida de resultados Esta tecnología puede incorporar cientos y hasta miles de cores con gran capacidad de cómputo y un gran ancho de banda a la memoria. Por esta razón se esta utilizando este recurso para mejorar las capacidades de respuesta a las necesidades cómputo de muchos programas que requieren esta posibilidad. CONCEPTOS BÁSICOS Una CPU nunca se puede reemplazar por completo por una GPU: una GPU complementa la arquitectura de la CPU al permitir que los cálculos repetitivos dentro de una aplicación se ejecuten en paralelo mientras el programa principal continúa ejecutándose en la CPU Se puede pensar en la CPU como el maestro de tareas de todo el sistema, coordinando una amplia gama de tareas informáticas de propósito general, con la GPU realizando una gama más estrecha de tareas más especializadas (generalmente matemáticas). Usando el poder del paralelismo, una GPU puede completar más trabajo en la misma cantidad de tiempo en comparación con una CPU. La principal diferencia entre la arquitectura de CPU y GPU es que una CPU está diseñada para manejar una amplia gama de tareas rápidamente (medida por la velocidad de reloj de la CPU), pero está limitada en la concurrencia de tareas que se pueden ejecutar. Una GPU está diseñada para generar imágenes y videos de alta resolución al mismo tiempo y de forma rápida.
¿Qué es la programación paralela?
Es un paradigma de solución, donde un problema se lo divide en varios procesos, cada proceso se divide en diferentes instrucciones, y las instrucciones de cada parte se ejecutan simultáneamente en diferentes procesadores, en el sentido más simple, la computación paralela es el uso simultáneo de múltiples recursos computacionales para resolver un problema computacional. Inicialmente para aplicar este paradigma se necesitaba de varios computadores, pero en la actualidad con los recursos ofrecidos por la GPU ya se la puede aplicar a un solo computador Hay varias formas diferentes de computación paralela: paralelismo a nivel de bit, paralelismo a nivel de instrucción, paralelismo de datos y paralelismo de tareas. Los programas informáticos paralelos son más difíciles de escribir que los secuenciales, porque la concurrencia introduce nuevos tipos de errores de desarrollo de software CONCEPTOS BÁSICOS ¿Por qué se hace programación paralela? La programación paralela es una alternativa ante la demanda continua de un poder computacional superior en áreas tan importantes como la predicción meteorológica, biocomputación, astrofísica, entre otras áreas. Las computadores secuenciales convencionales han venido aumentando considerablemente su velocidad aunque no en relación con sistemas cada vez más complejos que requieren mayor tiempo de cómputo. Ventajas Desventajas • Resuelve problemas que no se podrían realizar en una • Mayor consumo de energía sola CPU • Mayor dificultad a la hora de escribir programas • Resuelve problemas que no se pueden resolver en un • Dificultad para lograr una buena sincronización y comunicación tiempo razonable entre las tareas • Permite ejecutar problemas de un orden y complejidad • Retardos ocasionados por comunicación ente tareas mayor • Número de componentes usados es directamente proporcional a • Permite ejecutar código de manera más rápida los fallos potenciales (aceleración) • Condiciones de carrera (ocurre cuando dos o más procesos • Permite ejecutar en general más problemas acceden a un recurso compartido sin control) • Obtención de resultados en menos tiempo • Múltiples procesos se encuentran en condición de carrera si el • Permite la ejecución de varias instrucciones en resultado de los mismos depende del orden de su llegada simultáneo • Si los procesos que están en condición de carrera no son • Permite dividir una tarea en partes independientes correctamente sincronizados, puede producirse una corrupción de datos CONCEPTOS BÁSICOS TAMAÑO DE REGISTRO DEL PROCESADOR PARALELISMO A NIVEL DE INSTRUCCIÓN Este tipo de paralelismo consiste en cambiar el orden de las instrucciones de un programa y juntarlas en grupos para posteriormente ser ejecutados en paralelo sin alterar el resultado final del programa. Pipelining (Canalización) El pipelining proviene de la idea de que en una tubería no es necesario PARALELISMO A NIVEL DE BIT: esperar a que todo el agua dentro salga, para que pueda entrar más. Se habla de paralelismo al nivel de bit, cuando se Los procesadores modernos tienen un 'pipeline' que separa las aumenta el tamaño de la palabra del procesador instrucciones en varias etapas, donde cada etapa corresponde a una (tamaño de la cadena de bits a procesar). Este acción diferente que necesita la salida de la anterior. aumento reduce el número de instrucciones que tiene Ejemplo: Un pipeline de 5 etapas: fetch (buscar la instrucción), decode que ejecutar el procesador en variables cuyos (decodificarla), execute (ejecutarla), write (escribir en memoria el tamaños sean mayores a la longitud de la cadena. resultado de la operación). Ejemplo: En un procesador de 8-bits sumar dos números de 16bits tomaría dos instrucciones. En un procesador de 16-bits esa operación requiere solo una instrucción. Nota: este método está “estancado” desde el establecimiento de las arquitecturas de 32 y 64 bits. En el gráfico anterior se observa el procesamiento de dos instrucciones sin pipeline, tomando un tiempo de 8 ciclos, y con pipeline reduciendo este tiempo a solo 5 ciclos. CONCEPTOS BÁSICOS PARALELISMO A NIVEL DE DATOS En sistemas operativos, un hilo o hebra (del inglés thread), proceso ligero o subproceso es una secuencia de tareas encadenadas muy pequeña que Cada procesador realiza la misma tarea sobre un puede ser ejecutada por un sistema operativo. subconjunto independiente de datos. Ejemplo: Dos granjeros se dividen el área de césped a podar.
PARALELISMO A NIVEL DE TAREAS
Cada hilo realiza una tarea distinta e independiente de las demás. Ejemplo: Un granjero poda el césped, el otro cosecha. Hilo de control Computar hilo Los distintos hilos de ejecución comparten una serie de recursos tales como el Tarea espacio de memoria, los archivos abiertos, la situación de autenticación, etc. Tarea Tarea G Esta técnica permite simplificar el diseño de una aplicación que debe llevar A C a cabo distintas funciones simultáneamente. Tarea F Vacío Tarea B Un ejemplo de aplicación de esto es la escritura de un documento en Word Tarea E cuando se termina de escribir una palabra se ejecuta un hilo que verifica si Tarea la palabra tiene errores para subrayarla, este y otros hilos se están D ejecutando al mismo tiempo que usted esta trabajando con el procesador de texto. Procesamiento en hilos LA CLASE THREAD EN JAVA La forma más directa para hacer un programa multihilo es extender la clase Thread, y redefinir el método run(). Este método es invocado cuando se inicia el hilo (mediante una llamada al método start() de la clase Thread). El hilo se inicia con la llamada al método run() y termina cuando termina éste. Suponga que se desea ver un listado de 100 imágenes que se descargan ¿Cómo se desarrolla un programa con hilos? desde el Internet, como usuario ¿Cuál de las dos opciones siguientes Primer plano: Aquí se ejecuta únicamente un hilo llamado “hilo elegirías? principal”. Aquí hemos programado siempre, sin conocimiento de que estábamos trabajando ya con hilos. Aquí es donde el usuario A. Descargar las imágenes 100 interacciona de manera directa, además todo lo que pase aquí lo ve imágenes, haciendo esperar al y lo siente. usuario con una pantalla de “cargando…” hasta que se Segundo plano (o en inglés background): Se ejecuta todo el resto descargan todas. Luego podrá de hilos. El segundo plano tiene la característica de darse en el ver el listado con las imágenes. mismo momento que el primer plano. Aquí los hilos deberían de llevar las ejecuciones pesadas de la aplicación. El segundo plano el usuario no lo ve, es más, ni le interesa, para el usuario no existe. B. Que mientras se descargan las 100 imágenes, el usuario pueda no confundamos el término proceso con hilo. Un proceso es el ir viendo y usando las que ya se programa o aplicación en ejecución (Lo que llamamos aplicación es el han descargado. fichero ejecutable almacenado en memoria. Varios procesos pueden ejecutar varias instancias del mismo programa, es decir, como cuando se abren varias ventanas de un Bloc de notas o un Word). Así, se deduce y es verdad que un proceso contiene un hilo –mínimo el hilo principal que corre en primer plano- o varios hilos -El principal más La B es lo que todo usuario quiere de una aplicación, tener que esperar no algunos en segundo plano. es una opción. Ejemplo de hilos: El siguiente código muestra el funcionamiento de dos hilos en segundo plano, es una forma simple de mostrar como se aplican los procesos que se ejecutan en segundo plano, el ejemplo solo muestra mensajes, pero se pretende que sirva para mostrar la secuencia de ejecución de los dos hilos, se debe entender que no es bueno utilizar los hilos para mostrar mensajes, sino para obtener resultados de procesos que podrían tomar más tiempo de lo normal en el primer plano. package mihilo; //Los objetos de Hilo se pueden ejecutar en sus propios hilos porque Hilo implementa Runnable. class Hilo implements Runnable { String nombreHilo; // Constructor Hilo(String nombre){ El nombre es solo para identificar el proceso y es asignado al momento de crear la instancia nombreHilo=nombre; } Esto es solo para mostrar cuando empieza a ejecutar el hilo //Los hilos comienzan a ejecutarse aquí @Override public void run(){ System.out.println("Comenzando "+nombreHilo); try { El proceso del hilo solo consiste en mostrar 10 veces el for (int contar=0; contar<10; contar++){ nombre del hilo, por la velocidad del proceso se aplica un Thread.sleep(400); retardo o pausa de 400 milisegundos con sleep System.out.println("En "+nombreHilo+", el recuento "+contar); } }catch (InterruptedException exc){ En caso de que ocurra un problema en su ejecución mostrará “Interrumpido” caso contrario mostrará que ha System.out.println(nombreHilo + "Interrumpido."); terminado } System.out.println("Terminando "+nombreHilo); } } Ejemplo de hilos: package mihilo; public class MiHilo { Conceptualmente este es el Hilo principal (ejecución normal)
public static void main(String[] args) {
System.out.println("Hilo principal iniciando."); Estos objetos deben tener un método run() para que se pueda ejecutar en segundo plano //Primero, construye objetos de tipo Hilo. Hilo h1=new Hilo("Primer Hilo"); Hilo h2=new Hilo("Segundo Hilo"); Esto crea los hilos internos para su ejecución con los objetos que //Luego, construye los 2 hilo de ese objeto. se ejecutarán Thread nuevoH1=new Thread(h1); Thread nuevoH2=new Thread(h2); //Finalmente, comienza la ejecución de los hilos. A partir de aquí se ejecutaran en segundo plano los hilos, nuevoH1.start(); después de llamar a start(), la ejecución vuelve a main() nuevoH2.start(); for (int i=0; i<50;i++){ Este proceso es una fachada del hilo principal, simplemente System.out.print(" ."); muestra 50 puntos en pantalla try{ Thread.sleep(100); Esta pausa se la puso para obligar observar la mezcla de ejecución del hilo principal y los dos hilos secundarios }catch (InterruptedException exc){ System.out.println("Hilo principal interrumpido."); } } En caso de que ocurra algún problema en la ejecución del hilo principal se mostrará el respectivo mensaje System.out.println("Hilo principal finalizado."); } } Ejemplo de hilos: run: Hilo principal iniciando. .Comenzando Primer Hilo Comenzando Segundo Hilo En este ejemplo se muestra la ejecución de los tres hilos, el . . .En Primer Hilo, el recuento 0 principal (negro) y el primer hilo secundario (Rojo) y el En Segundo Hilo, el recuento 0 . . . .En Segundo Hilo, el recuento 1 segundo hilo secundario (Celeste), los tres procesos se En Primer Hilo, el recuento 1 ejecutan de forma simultanea por lo que notará que no . . . .En Primer Hilo, el recuento 2 existe simetría de los proceso. En Segundo Hilo, el recuento 2 . . . .En Primer Hilo, el recuento 3 En Segundo Hilo, el recuento 3 . . . .En Segundo Hilo, el recuento 4 En Primer Hilo, el recuento 4 . . . .En Primer Hilo, el recuento 5 En Segundo Hilo, el recuento 5 . . . .En Segundo Hilo, el recuento 6 En Primer Hilo, el recuento 6 . . . .En Primer Hilo, el recuento 7 En Segundo Hilo, el recuento 7 . . . .En Primer Hilo, el recuento 8 En Segundo Hilo, el recuento 8 . . . .En Primer Hilo, el recuento 9 Terminando Primer Hilo En Segundo Hilo, el recuento 9 Terminando Segundo Hilo . . . . . . . . . .Hilo principal finalizado. BUILD SUCCESSFUL (total time: 5 seconds) CONCEPTOS BÁSICOS En este ejemplo, observará que se quita la pausa en la ejecución del for() en el hilo principal por lo que al ejecutarlo mostrará otro resultado: run: package mihilo; Hilo principal iniciando. public class MiHilo { . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Comenzando Primer Hilo public static void main(String[] args) { Comenzando Segundo Hilo Hilo principal finalizado. System.out.println("Hilo principal iniciando."); En Primer Hilo, el recuento 0 En este ejemplo se muestra la //Primero, construye objetos de tipo Hilo. En Segundo Hilo, el recuento 0 Hilo h1=new Hilo("Primer Hilo"); En Segundo Hilo, el recuento 1 prioridad de ejecución del hilo Hilo h2=new Hilo("Segundo Hilo"); En Primer Hilo, el recuento 1 principal, recuerde que el propósito //Luego, construye los 2 hilo de ese objeto. En Primer Hilo, el recuento 2 de la ejecución en segundo plano Thread nuevoH1=new Thread(h1); En Segundo Hilo, el recuento 2 consiste en desarrollar procesos no Thread nuevoH2=new Thread(h2); En Segundo Hilo, el recuento 3 En Primer Hilo, el recuento 3 visibles para el usuario, observe //Finalmente, comienza la ejecución de los hilos. que el hilo principal termina En Segundo Hilo, el recuento 4 nuevoH1.start(); En Primer Hilo, el recuento 4 primero pero aún así no termina nuevoH2.start(); En Primer Hilo, el recuento 5 for (int i=0; i<50;i++){ En Segundo Hilo, el recuento 5 hasta que terminen los hilos System.out.print(" ."); En Primer Hilo, el recuento 6 secundarios. }try{ En Segundo Hilo, el recuento 6 Thread.sleep(100); En Primer Hilo, el recuento 7 En Segundo Hilo, el recuento 7 }catch (InterruptedException exc){ En Segundo Hilo, el recuento 8 System.out.println("Hilo principal interrumpido."); En Primer Hilo, el recuento 8 } En Segundo Hilo, el recuento 9 System.out.println("Hilo principal finalizado."); Terminando Segundo Hilo } En Primer Hilo, el recuento 9 } Terminando Primer Hilo