Learning SynchronizationContext, async y await

La programación asincrónica es una forma de programación paralela que le permite ejecutar tareas separadas del hilo principal de la aplicación y luego notifica al hilo cuando finaliza su ejecución. La asincronía le ayuda a ejecutar tareas sin la necesidad de detener el flujo de ejecución o la capacidad de respuesta de su aplicación.

Microsoft ha proporcionado soporte para la programación paralela en .Net Framework para aprovechar los beneficios de los sistemas de múltiples núcleos. Puede aprovechar la asincronía para mejorar el rendimiento y la capacidad de respuesta de su aplicación.

Básicamente, hay dos tipos posibles de operaciones en una aplicación. Éstas incluyen operaciones vinculadas a cálculo y operaciones vinculadas a E / S. Las operaciones vinculadas al cálculo son aquellas en las que el cálculo se puede realizar en un subproceso separado para que el subproceso principal pueda continuar con su ejecución. Por el contrario, las operaciones vinculadas de E / S son aquellas en las que se ejecutan externamente y, por lo tanto, no necesitan bloquear el hilo actual mientras la E / S está en curso.

Contexto de sincronización y contexto de ejecución

Cada hilo tiene un contexto asociado con él, esto también se conoce como el contexto "actual", y estos contextos se pueden compartir entre hilos. ExecutionContext contiene metadatos relevantes del entorno o contexto actual en el que se ejecuta el programa. SynchronizationContext representa una abstracción: denota la ubicación donde se ejecuta el código de su aplicación.

Un SynchronizationContext le permite poner en cola una tarea en otro contexto. Tenga en cuenta que cada hilo puede tener su propio SynchronizatonContext. La clase SynchronizationContext se ha agregado recientemente al espacio de nombres System.Threading y facilita la comunicación entre subprocesos. Puede leer más sobre SynchronizationContext y ExecutionContext aquí.

Una inmersión profunda en Async y Await

Los tres patrones de programación asincrónica incluyen lo siguiente:

  1. Modelo de programación asincrónica (APM)
  2. Patrón asincrónico basado en eventos (EAP)
  3. Patrón asincrónico basado en tareas (TAP)

El último, el recomendado y también el más elegante de todos es el TAP.

Tenga en cuenta que puede marcar un método con la palabra clave "async" que devuelve void, Task o Task. Tenga en cuenta que cuando ocurre una excepción dentro de un método asincrónico que tiene un tipo de retorno de Tarea o Tarea, los detalles de la excepción se almacenan dentro de la instancia de Tarea.

Por el contrario, cuando se produce una excepción dentro de un método asincrónico que tiene un tipo de retorno de vacío, los detalles de la excepción se almacenan dentro del SynchronizationContext que estaba activo en el momento en que se llamó al método asincrónico. En esencia, no puede manejar excepciones generadas dentro de un método asincrónico que tiene un tipo de retorno de vacío utilizando controladores de excepciones escritos dentro del método asincrónico. Debido a las diferentes semánticas de computación y manejo de errores, es aconsejable evitar los métodos asincrónicos que tienen tipos de retorno nulos a menos que haya una razón suficiente para usarlos.

Cuando usa la palabra clave "await" dentro de un método asincrónico, el método se divide dentro de una máquina de estado. Tenga en cuenta que la palabra clave "await" captura el SynchronizationContext actual y tan pronto como se completa la tarea que se ha esperado con la palabra clave "await", la máquina de estado se reanuda y se reinicia la ejecución del código en el método de la persona que llama; esto también es conocido como continuación. Si la ejecución del código que se ha esperado utilizando la palabra clave "await" se ha completado en el momento en que se encuentra el punto de suspensión, el método asincrónico (el método que se ha marcado como "async") se ejecuta de forma sincrónica. Si la ejecución del código que se esperaba no se completa, se adjunta un delegado de continuación al código que se esperaba.

Puede aprovechar los métodos asincrónicos que devuelven void para crear controladores de eventos asincrónicos. El método Main no se puede marcar con la palabra clave "async" ya que es el punto de entrada de la aplicación; un método Main "async" terminaría en el momento en que se llama. La palabra clave "await" informa al compilador que el método puede tener un punto de suspensión y reanudación. Por cierto, puede usar la palabra clave "await" solo en un método que se haya marcado como asíncrono usando la palabra clave "async".

Cuando se llama a un método asíncrono, se ejecuta de forma sincrónica en el hilo actual independientemente del tipo de retorno del método. Cuando marca un método como asincrónico usando la palabra clave "async", simplemente informa al compilador que el método se puede dividir en varias tareas; algunas de estas tareas pueden ejecutarse de forma asincrónica. Además, la inclusión de la palabra clave "async" en un método no pone en cola la invocación del método como parte del grupo de subprocesos. La asincronía (es decir, si un método tendría un comportamiento asincrónico) en realidad depende del punto de suspensión que ha mencionado en su método utilizando la palabra clave "await". Si no incluye la palabra clave "await" dentro de un método asincrónico, todo el método se ejecutará sincrónicamente.