Está en la página 1de 14

¿Qué es concurrencia?

• En programación hablamos de concurrencia cuando se ejecuta más de una tarea al


mismo tiempo.
• Esta habilidad es útil cuando necesitamos que una aplicación haga alguna cosa mientras
está trabajando en algo más.
• La concurrencia es un aspecto clave de las aplicaciones modernas, permite que:
• Los usuarios finales puedan interactuar con la interfaz de usuario de manera no-bloqueante.
• Un servidor pueda atender varias peticiones en simultáneo y no afectar los tiempos de respuesta
ante períodos de alta demanda.
• Realizar tareas de cómputo complejas de manera más rápida y haciendo un uso más eficaz los
recursos de la computadora.
• La programación multi-hilo <multithreaded programming> y programación
asincrónica <asynchronous programming> son las dos formas de concurrencia más
comunes.
Secuencial vs Concurrente
• Los programas secuenciales ejecutan
una operación detrás de otra (en
secuencia), aunque el orden puede
variar (if, while), solo hacen una sola
cosa a la vez, es decir solo hay un flujo
de ejecución.
• Un programa concurrente hace varias
cosas al mismo tiempo, varias
actividades que progresan en paralelo,
estos programas tienen varios flujos de
ejecución (threads), cada uno de ellos
ejecuta una secuencia de operaciones.
¿Cómo se da la concurrencia?
• En un sistema con varios procesadores se puede ejecutar una tarea en cada
procesador, esto es ejecución simultánea (paralelismo físico).

• En un monoprocesador se intercalan las operaciones de las tareas, esto es


multiplexado en tiempo (paralelismo lógico), o multicore si tiene varios cores.

• La máquina virtual (o el sistema operativo) se encarga de los detalles, desde


un punto de vista lógico son equivalentes.
¿Para qué se usa?
• Interfaces de usuario reactivas
• Atención a sucesos asíncronos
• Gestión de ventanas, widgets, etc.
• Servidores
• Atención a múltiples clientes
• Gestión de protocolos de comunicación
• Mejoras de prestaciones
• Ejecución en multiprocesadores
• Cálculos complejos
• Ejecución de algoritmos complejos en paralelo
Hilos vs Procesos
• Los procesos del sistema se ejecutan en paralelo en la computadora y
se mantienen separados unos de otros y comparten la memoria del
sistema.
• Los hilos (threads) se ejecutan en paralelo en un proceso, y
comparten memoria del proceso que los contiene
• El Thread Scheduler es quien se encarga de asignar tiempos de
ejecución y que los hilos no se queden colgados.
Programación multi-hilo
• Un proceso es un programa en ejecución que tiene asignados recursos tales
como memoria e hilos.
• Un hilo (thread), también llamado hebra o subproceso, es la unidad básica a
la que un sistema operativo asigna tiempo de procesamiento. Son los
encargados de ejecutar nuestro código sentencia a sentencia.
• Por defecto cada proceso tiene un único hilo, es decir, sólo puede procesar
una tarea a la vez. La programación multi-hilo (multithreaded
programming) permite que un proceso se ejecute sobre múltiples hilos y
cada uno de esos hilos esté realizando una tarea distinta en paralelo.
• Todos los hilos de un mismo proceso comparten los mismos recursos
asignados por el sistema operativo.
Multitarea apropiativa
• Por cada núcleo de la CPU, se puede ejecutar a lo mucho un proceso en cada
momento. Windows y otros sistemas operativos modernos simulan la ejecución
paralela de tareas dividiendo el tiempo de procesamiento entre los hilos,
permitiendo que se vayan ejecutando uno después de otro en pequeñas
fracciones de tiempo. El hilo que se está ejecutando es suspendido cuando
termina su fracción de tiempo, luego el procesador permite que otro hilo se
ejecute por el mismo periodo de tiempo. Esta forma de simular el paralelismo
recibe el nombre de multitarea apropiativa (preemptive multitasking).
• Cuando Windows cambia de un hilo a otro, guarda el contexto donde se ejecutó
el hilo actual y recarga el contexto del próximo hilo en la cola de ejecución. Hay
que ser conscientes de que esto también consume tiempo y recursos.
• Cada hilo tiene una pila de ejecución (call stack) independiente, esto
significa que cada uno maneja su propia secuencia de funciones a
ejecutar.
• En algunos tipos de aplicación existen hilos especiales, por ejemplo un
hilo para la interfaz de usuario (UI Thread) o el hilo principal en los
programas de consola (Main Thread).
• Todas las aplicaciones de .NET tienen un conjunto de hilos (thread pool)
que se encarga de mantener un número de hilos activos esperando para
ejecutar cualquier trabajo que se requiera. Lo podemos ver como un lugar
donde podemos poner en cola tareas a realizar y que se ajustará
automáticamente de acuerdo a la demanda.
• En .NET se solía utilizar la clase Thread para trabajar con hilos, la cual
es una abstracción de bajo nivel. El thread pool es una abstracción de
un nivel un poco más alto, ya que se encargará por si mismo de
instanciar un hilo si existe la necesidad. Actualmente no se
recomienda crear instancias de Thread ya que existen nuevas
soluciones que fueron afinadas para cubrir de forma eficiente y
sencilla la gran mayoría de los escenarios reales.
• Las clases con las que trabajaremos son abstracciones de alto nivel
que ponen en cola trabajo para que sea resuelto por el thread pool.
Programación asíncrona
• La programación multi-thread implica el reparto de tareas (thread) de una misma
aplicación, de forma que se realicen de manera independiente unas de otras. De este
modo se consigue un uso más óptimo del tiempo del procesador. Las tareas no se
realizan en realidad de forma paralela. El procesador asigna un tiempo de
procesamiento a cada tarea en función de su importancia. Este cambio de contexto
implica que el procesador memoriza la pila de la tarea actual antes de restaurar la de
la tarea a la que le da paso.
• C# 5 introduce de nuevo palabras reservadas (await y async) para facilitar el
desarrollo asíncrono. El desarrollo síncrono implica que una función que se invoca
bloquea la ejecución del programa hasta que aquella termina. Cuando una función
se invoca de forma asíncrona, la ejecución del programa principal continúa. Por
tanto, existe una noción de ejecución en paralelo y de concurrencia, como ocurre
con la programación multi-thread.
La clase Thread
• El espacio de nombres System.Threading alberga clases que permiten crear y controlar
las tareas, principalmente mediante la clase Thread. Los threads se deben usar cuando
una aplicación debe gestionar varias tareas independientes, como gestionar una interfaz
de usuario o realizar un tratamiento de datos. La aplicación tendrá mejor rendimiento si
estas dos tareas se desarrollan en threads específicos.
• El delegado ThreadStart se emplea para crear un nuevo thread. Su constructor toma
como argumento la declaración del método que se ejecutará en este nuevo thread:
• ThreadStart newThread = new ThreadStart(OtherThread);
• El delegado se pasa a continuación como argumento del constructor del objeto Thread:
• Thread thread = new Thread(newThread);
• A continuación, se llama al método Start
Funciones asíncronas
• Las funciones asíncronas permiten mejorar la reactividad de una aplicación. Es frecuente tener
que efectuar, en una aplicación, procesamientos relativamente largos. Con un modelo de
desarrollo clásico, la aplicación completa se bloquea esperando a que termine el procesamiento.
Esta situación es molesta para el usuario. No sabe, realmente, qué está haciendo la aplicación. Si
quiere detener la aplicación durante este tiempo de bloqueo, no tiene más opción que utilizar el
administrador de tareas de Windows.
• Para evitar esta situación, a partir de la versión 5 del lenguaje C# es posible definir funciones
asíncronas. La palabra reservada async incluida en la firma de una función hace que su ejecución
se produzca de forma asíncrona. Para que este mecanismo sea realmente eficaz hace falta,
además, indicar en el interior de este tipo de función al menos una ubicación donde pueda
suspenderse la ejecución y esperar a que el procesamiento termine. La palabra reservada await
situada delante de una expresión indica estos puntos de interrupción. Cuando termina el
procesamiento, se evalúa la expresión y se retoma la ejecución de la función. Para que este
mecanismo funcione, es preciso que la expresión genere un tipo Task<...>.
Asincronía en C#

Método ASYNC AWAIT - TASK


• Un método async quiere estar • Un método asíncrono tiene que
en sincronía con métodos devolver un objeto del tipo Task
asíncronos • Await le indica al método async
• ¿Qué significa estar en sintonía que debe esperar a un método
con un método asíncrono? asíncrono que devuelve un Task.
• Suspenderse y esperar a que un Cuando el método se completa,
proceso asíncrono que él mismo await se encarga de obtener el
ha iniciado se termine para luego resultado de dicho método.
reanudarse
Programación en paralelo
• La programación en paralelo (parallel programming) es un tipo de programación multi-hilo, que a
su vez es una forma de concurrencia. Se utiliza cuando se necesita dividir una gran carga de trabajo
computacional en partes independientes y ejecutarlas en paralelo, maximizando el uso de los
núcleos de la CPU.
• La programación en paralelo nos sirve para dividir una tarea en distintas partes y trabajar esas
partes de manera simultánea.
• Beneficio: Ahorrar tiempo
• No es recomendable usar paralelismo en ambientes web: ASP.NET y ASP.NET Core
• Librería de Tareas en Paralelo
• PLINQ (LINQ en paralelo)
• Paralelismo de Datos
• Paralelismo de Tareas
• No siempre debemos usar paralelismo

También podría gustarte