La programación asíncrona es un tema amplio y ampliamente discutido, pero los ingenieros de software todavía están buscando la mejor manera de implementar esta idea e integrarla en las aplicaciones.

Como ingeniero de software sénior, tenía curiosidad acerca de cómo era posible hacer varias cosas al mismo tiempo, y probablemente no soy el único que hace esta pregunta. Todos se esfuerzan por ser más productivos y quieren lo mismo de sus aplicaciones.

Centrándonos en la asincronía en Java, descubriremos muchas formas de implementarla y diferentes casos de uso.

Sincronicidad vs asincronía

La programación síncrona (Sync) y asíncrona (Async) se puede realizar en uno o más subprocesos. La principal diferencia es que con la programación síncrona, realizamos una tarea a la vez, mientras que con la programación asíncrona, se realizan varias tareas simultáneamente. Por ejemplo:

Sincronicidad :

  • Subproceso único : estoy empezando a hervir un huevo. Una vez que esté cocido, puedo empezar a tostar el pan. Tengo que esperar a que se complete una tarea antes de comenzar otra.
  • Multihilo : Comienzo a hervir un huevo, y después de que esté hervido, mi madre tostará el pan. Las tareas se ejecutan una tras otra y por diferentes personas (hilos).

asincronía :

  • De un solo hilo : Pongo el huevo a hervir y pongo un temporizador, pongo el pan en la tostadora y enciendo otro temporizador, y cuando se acabe el tiempo, comeré. En el modo asíncrono, no tengo que esperar a que se complete una tarea para comenzar otra.
  • Multihilo : contrato a dos chefs para que me cocinen un huevo y tuesten mi pan. Pueden hacerlo al mismo tiempo y uno no tiene que esperar a que el otro comience.

Asincronía con hilos

La primera forma de implementar la asincronía en Java es usar la interfaz de subprocesos Runnabley la clase Thread, que está disponible desde JDK 1.0. Cualquier clase puede implementar Runnabley anular un método, run()o extender una clase Thready hacer lo mismo.

La diferencia es que cuando runse llama a un método directamente desde Runnable, no se crea un nuevo subproceso, sino que el método se ejecuta en el subproceso desde el que se llamó. Sin embargo, si usamos thread.start(), se creará un nuevo hilo.

Para un mejor control de flujo en JDK 1.5, puede usar ejecutores ( Executor). Utilizan diferentes grupos de subprocesos y ayudan a evitar la necesidad de crear manualmente un subproceso. En su lugar, podemos especificar cuántos subprocesos necesitamos, y el ejecutor reutilizará estos subprocesos durante todo el tiempo que se ejecute la aplicación.

Asincronía con el Futuro

run()es un método vacío y no puede devolver nada de un subproceso, pero si necesitamos el resultado de un cálculo realizado en un subproceso diferente al main, entonces necesitaremos usar el Callable. La respuesta de la tarea no está disponible de inmediato y, alternativamente, Callabledevolverá un objeto futuro Futurecuando se envíe al servicio de ejecución. Este objeto promete que cuando se completen los cálculos, obtendremos su resultado, solo llame a get(). Este no es un buen uso de la asincronía, ya que get()bloquea el hilo actual hasta que recibe una respuesta. Sin embargo, existe una solución a través del método future.isDone()  : comprueba constantemente si el cálculo se ha completado y, solo cuando este método devuelve el valor trueget()devuelve el resultado.

Asíncrono con CompletableFuture

En JDK 1.8, el objeto Future se actualizó para convertirse en un CompletableFuture, que, además del objeto futuro, también implementa una etapa de finalización ( CompletionStage). CompletionStageofrece una variedad de métodos para simplificar el trabajo con respuestas calculadas en diferentes subprocesos y etapas. Algunas de las más comunes son thenApply(), que es similar a las funciones map()de flujos, así como thenAccept(), que es similar a foreach. Hay varias formas de obtener una respuesta CompletableFuture. Algunos realizan la tarea en un subproceso diferente, otros no, pero tienen una cosa en común: si ocurren excepciones durante el cálculo, los usuarios pueden manejarlas.

Asíncrono con @Async

Otra forma de implementar la asincronía es una anotación @Asyncde Spring Framework. Solo se puede usar en métodos públicos, en cuyo caso no estará disponible llamar a métodos de la misma clase en la que están definidos. Cualquier código dentro de un método anotado con @Asyncse ejecutará en un subproceso diferente y puede que no sea válido o no devuelva CompletableFuture. Entonces es una alternativa a crear CompletableFuturey darle un método para ejecutar, pero para poder usar esta anotación, se necesita algo más: @EnableAsyncen la clase de configuración.

Spring Events

Spring Events para implementar la asincronía es un paso adelante que también ofrece una forma de reducir el acoplamiento y la facilidad de agregar nuevas funciones sin cambiar las existentes.

Se requieren tres elementos:

  • Evento ( Event) - puede ser cualquier objeto que se extienda ApplicationEvent.
  • El editor ( Publisher) es el componente que publicará el evento usando el componente ApplicationEventPublisher.
  • Un listener ( Listener) es un componente que contiene un método con la anotación @EventListenery ayuda a definir una tarea que se ejecutará cuando ocurra un determinado evento.

Otra forma de hacer que el oyente sea asíncrono es agregar un bean a la configuración SimpleApplicationEventMulticastery asignarle un archivo TaskExecutor. Una vez que este bean está en su lugar, no hay necesidad de anotar cada lista de eventos con @Async, y todos los eventos se manejarán en un subproceso diferente. Si no desea omitir @Asyncla anotación de algún método, será útil utilizar este método, pero tenga en cuenta: este enfoque hará que el procesamiento de todos los eventos, incluso los eventos del marco, sea asíncrono. El uso de la anotación nos permitirá elegir qué eventos se procesarán de forma síncrona y cuáles de forma asíncrona.

Microservicios

A nivel de microservicio, también existe la opción de elegir entre síncrono y asíncrono. La diferencia entre los dos es que, como dice la definición, asíncrono significa que no esperamos una respuesta inmediata del servicio llamado, mientras que síncrono significa que sí.

Una de las comunicaciones síncronas más populares entre microservicios es a través de llamadas REST. Para la comunicación asíncrona, puede usar colas o temas. Ambos contienen mensajes, pero la diferencia es que un mensaje de una cola solo puede ser procesado por un suscriptor, mientras que un mensaje de un tema puede ser leído por varios suscriptores.

Pros y contras de la asincronía

Vale la pena considerar la programación asíncrona cuando desea delegar una tarea a otro subproceso porque consume mucho tiempo o si no desea que el resultado de una tarea afecte el subproceso de la aplicación actual. Esto le permitirá realizar varias operaciones al mismo tiempo. Con la asincronía, puede separar tareas y componentes, lo que mejora el rendimiento general de la aplicación.

Alternativamente, debe tener en cuenta que la depuración y la escritura de pruebas se vuelven más difíciles en el código con métodos asincrónicos, pero esto no debe convertirse en un obstáculo para elegir una solución.

Y el último

¡Los subprocesos se tratan de trabajadores (trabajadores) y la asincronía se trata de tareas!

Compartir:
Categorías: Programación

0 comentarios

Deja una respuesta

Marcador de posición del avatar

Tu dirección de correo electrónico no será publicada.

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.