Más allá de los subprocesos tradicionales: exploración del potencial ilimitado de las corrutinas de Java Loom (fibras/subprocesos virtuales)

"Más allá de los subprocesos tradicionales: exploración del potencial infinito de las corrutinas de Java Loom (fibras/subprocesos virtuales)"

1. La historia del desarrollo de las corrutinas de Java

El proceso de desarrollo de corrutinas Java se puede resumir en las siguientes etapas:

  • En 1963 se propuso formalmente el concepto de corrutinas, y su nacimiento fue incluso anterior al de hilos.
  • En 2007, se lanzó el proyecto Kilim, que es un marco de rutina de Java basado en tecnología de mejora de bytecode.
  • En 2014, se lanzó el proyecto Quasar, que es un marco de corrutina Java basado en la tecnología Agent.
  • En 2016, se lanzó el proyecto Project Loom, que es un proyecto destinado a proporcionar soporte nativo de corrutina para Java.
  • En 2019, el lenguaje Kotlin lanzó la versión 1.3, que es un lenguaje compatible con Java que admite la programación corrutina.
  • En 2020, se lanzará Java 15, que incluye la versión preliminar de Project Loom (Característica de vista previa), que proporciona funciones como Virtual Thread (Hilo virtual) y Scope Variable.
  1. Primeros intentos: en las primeras versiones de Java, la concurrencia se lograba principalmente a través de subprocesos y mecanismos de sincronización. Aunque Java proporciona compatibilidad con subprocesos múltiples, debido al alto costo de la creación y el cambio de subprocesos, esto hace que la eficiencia de procesamiento de las escenas de alta simultaneidad sea baja.
  2. Quasar (2011): Quasar es una biblioteca de rutinas de Java basada en la manipulación de códigos de bytes y la instrumentación de códigos de bytes desarrollada por Parallel Universe. Implementa un concepto similar a una corrutina en Java, mediante la manipulación de códigos de bytes para lograr corrutinas livianas y cambio de tareas. Quasar proporciona un método de programación de corrutinas que permite ejecutar múltiples corrutinas en un subproceso, evitando así la sobrecarga del cambio de subprocesos.
  3. Kotlin Coroutines (2017): Kotlin es un lenguaje de programación que se ejecuta en JVM, desarrollado por JetBrains. Kotlin Coroutines es un marco de programación asíncrono para Kotlin que permite escribir código asíncrono en forma de rutina. Aunque Kotlin es un lenguaje de programación independiente, se integra a la perfección con Java, por lo que puede usar Kotlin Coroutines en sus proyectos Java.
  4. Project Loom (en progreso): Project Loom es un subproyecto de OpenJDK dedicado a introducir subprocesos ligeros (llamados Subprocesos virtuales o Subprocesos de telar) en Java. El objetivo de Loom es agregar capacidades de fibra a Java sin cambiar los programas Java existentes. El objetivo de diseño de Loom es implementar un modelo de subprocesos liviano y de corrutina eficiente y fácil de usar para resolver los desafíos de la programación concurrente de Java.

Todavía no hay soporte nativo para corrutinas en la biblioteca estándar de Java. Sin embargo, el surgimiento de los proyectos y bibliotecas mencionados anteriormente muestra la demanda de la comunidad de Java de una programación concurrente eficiente, así como la exploración y práctica de la programación corrutina, y el desarrollo futuro de Java puede introducir mecanismos de concurrencia más avanzados para proporcionar a los desarrolladores experiencia de programación concurrente más elegante y eficiente.

2. Telar del proyecto Java

Java Project Loom es un importante proyecto del lenguaje Java, que tiene como objetivo mejorar el modelo de ejecución de la Máquina Virtual de Java (JVM) para admitir Threads Ligeros (Lightweight Threads), mejorando así el rendimiento y la escalabilidad de Java al tratar con la programación concurrente y paralela. Escalabilidad. Este artículo describe los antecedentes, los objetivos, las características principales y el impacto en los desarrolladores y aplicaciones de Java de Java Project Loom.

1. Antecedentes

En el desarrollo de Java, el subproceso (Thread) es un mecanismo de concurrencia de uso común que permite que los programas se ejecuten simultáneamente con múltiples rutas de ejecución independientes. Sin embargo, existen algunos problemas con el modelo tradicional de subprocesamiento de Java. Cada subproceso se asigna al subproceso nativo del sistema operativo, lo que genera una gran sobrecarga para crear y destruir subprocesos. Además, dado que cada subproceso ocupará una cierta cantidad de espacio de memoria, cuando el grado de concurrencia es alto, la creación de una gran cantidad de subprocesos puede provocar un consumo excesivo de memoria e incluso provocar la caída del sistema.

Para resolver estos problemas, nació el proyecto Java Project Loom.

El objetivo principal de Java Project Loom es introducir una implementación ligera de subprocesos llamada "Fibras" para optimizar el modelo de gestión y ejecución de subprocesos de Java. Las fibras son subprocesos de modo de usuario que son administrados por la máquina virtual de Java (JVM) y el sistema de tiempo de ejecución, y ya no es necesario asignarlos a subprocesos nativos del sistema operativo. De esta forma, la sobrecarga de creación y destrucción de Fibers se reducirá en gran medida, y se puede ejecutar una gran cantidad de Fibers dentro del mismo subproceso del sistema operativo, lo que reduce el consumo de memoria y mejora el rendimiento.

2. Características principales

Java Project Loom trae muchas características importantes, las más notables son:

2.1 Fibras

Las fibras son una característica central de Java Project Loom. Son una implementación ligera de subprocesos de usuario que se pueden crear, suspender, reanudar y cancelar a través de la API de Fiber. En comparación con los subprocesos tradicionales, los costos de creación y destrucción de fibras son más bajos y los recursos de subprocesos se pueden reutilizar de manera eficiente, de modo que las aplicaciones pueden tener miles o incluso millones de fibras ejecutándose simultáneamente sin una sobrecarga de memoria significativa.

2.2 Continuaciones

Para admitir Fibras, Java Project Loom introdujo el concepto de Continuaciones. Las continuaciones permiten guardar el estado de ejecución de una fibra mientras está suspendida y volver al estado suspendido cuando sea necesario. Esto proporciona un mecanismo eficiente para suspender y reanudar Fibers, evitando la sobrecarga del cambio de contexto de hilo tradicional.

2.3 Hilos virtuales

Java Project Loom también introduce el concepto de subprocesos virtuales, que es un mecanismo para la encapsulación transparente de fibras. Virtual Threads puede crear y administrar fibras dinámicamente de acuerdo con las necesidades de las aplicaciones, lo que permite a los desarrolladores usar un modelo de programación simple para manejar la concurrencia a gran escala sin preocuparse por los detalles de administración de subprocesos.

2.4 Subprocesos con alcance

Scoped Threads es otra característica importante de Java Project Loom, que permite que Fibers se ejecute dentro de un alcance limitado. De esta manera, la Fibra se destruirá automáticamente después de salir de su alcance, evitando así fugas de recursos y la complejidad de la gestión de subprocesos.

3. El impacto del Proyecto Telar

La introducción de Java Project Loom tendrá un profundo impacto en los desarrolladores y aplicaciones de Java:

3.1 Mayor rendimiento concurrente

Al introducir Fibras livianas, Java Project Loom permitirá que las aplicaciones de Java manejen una gran cantidad de tareas concurrentes de manera más eficiente, proporcionando así un mayor rendimiento concurrente y una mejor escalabilidad.

3.2 Menor consumo de memoria

Dado que ya no es necesario asignar fibras a los subprocesos nativos del sistema operativo, el consumo de memoria de las aplicaciones Java se reducirá significativamente, especialmente en escenarios de alta concurrencia, lo que será especialmente importante para entornos con recursos limitados y plataformas de computación en la nube.

3.3 Código más conciso

La introducción de Virtual Threads y Scoped Threads simplificará la lógica del código de la programación concurrente, lo que permitirá a los desarrolladores centrarse más en la lógica empresarial sin prestar demasiada atención a la gestión de subprocesos subyacentes.

3.4 Mejor capacidad de respuesta

La mejora de Java Project Loom hará que las aplicaciones de Java sean más receptivas, especialmente bajo una alta carga y alta concurrencia, la aplicación aún puede responder rápidamente a las solicitudes de los usuarios.

En general, Java Project Loom es un paso importante hacia una mayor concurrencia y un mejor rendimiento para el lenguaje Java. Al introducir Fibers y funciones relacionadas, brindará herramientas más poderosas a los desarrolladores de Java, lo que facilitará el desarrollo de aplicaciones Java eficientes y altamente concurrentes. Con el desarrollo continuo del ecosistema de Java, Java Project Loom seguramente se convertirá en una parte indispensable e importante del desarrollo de Java.

4, muestras

Muchas aplicaciones no usarán la API Thread directamente, sino que usarán las API java.util.concurrent.ExecutorService y Executors. La API de ejecutores se ha actualizado con un nuevo método de fábrica para ExecutorServices que inicia un nuevo subproceso para cada tarea. Los subprocesos virtuales son lo suficientemente económicos como para crear un nuevo subproceso virtual para cada tarea, sin necesidad de agrupar subprocesos virtuales.

Lo siguiente inicia un subproceso ficticio para imprimir el mensaje. Llama al método de unión para esperar a que finalice el subproceso.

Subproceso subproceso = Subproceso.ofVirtual().start(() -> System.out.println("Hola")); 
hilo.join();

Aquí hay un ejemplo que inicia un subproceso ficticio para poner en cola elementos después de una suspensión. El subproceso principal está bloqueado en la cola, esperando un elemento.

var cola = new SynchronousQueue<String>(); 
Thread.ofVirtual().start(() -> { 
    try { 
        Thread.sleep(Duration.ofSeconds(2)); 
        queue.put("done"); 
    } catch (InterruptedException e) { } 
}); 
 
Cadena mensaje = cola.tomar();

Thread.Builder API también se puede usar para crear ThreadFactory. El ThreadFactory creado por el siguiente fragmento creará subprocesos virtuales llamados "trabajador-0", "trabajador-1", "trabajador-2", etc.

Fábrica ThreadFactory = Thread.ofVirtual().name("worker", 0).factory();

El siguiente ejemplo usa Executors API para crear un ExecutorService que inicia un nuevo subproceso virtual para cada tarea. El ejemplo usa una construcción try-with-resources para garantizar que ExecutorService termine antes de continuar.

ExecutorService define el método de envío para ejecutar tareas. El método de envío no bloquea, pero devuelve un objeto Future que se puede usar para esperar un resultado o una excepción. El método Enviar que acepta una colección de tareas devuelve un Stream que se llena de forma perezosa con objetos Future completos que representan los resultados.

El ejemplo también usa los métodos de combinación de invocarTodos e invocarAny para realizar múltiples tareas y esperar a que se completen.

try (ExecutorService executor = Executors.newVirtualThreadExecutor()) { 
      // Envía una tarea que devuelve valor y espera el resultado 
    Future<String> future = executor.submit(() -> "foo"); 
    resultado de cadena = futuro.join(); 
 
    // Envía dos tareas que devuelven valor para obtener un Stream que se rellena con pereza 
    // con objetos Future completados a medida que las tareas se completan 
    Stream<Future<String>> stream = executor.submit(List.of(() -> "foo" , () -> "barra")); 
    stream.filter(Future::isCompletedNormally) 
            .map(Future::join) 
            .forEach(System.out::println); 
 
    // Ejecuta dos tareas de retorno de valor, esperando que ambas se completen
    List<Future<String>> resultados1 = executor.invokeAll(List.of(() -> "foo",
 
    // Ejecuta dos tareas de retorno de valor, esperando que ambas se completen. Si una de las 
    // tareas se completa con una excepción, la otra se cancela. 
    List<Future<String>> resultados2 = executor.invokeAll(List.of(() -> "foo", () -> "bar"), /*waitAll*/ false); 
 
    // Ejecuta dos tareas que devuelven valor, devolviendo el resultado de la primera 
    // para completar, cancelando la otra. 
    String first = executor.invokeAny(List.of(() -> "foo", () -> "bar")); 

}

3. Cómo utiliza SpringBoot las corrutinas

1. Proyecto Telar

Java Project Loom tiene como objetivo mejorar el modelo de ejecución de la máquina virtual Java, cuyo concepto central son las fibras, también conocidas como subprocesos ligeros. Fibers proporciona un modelo de subprocesos liviano que puede crear y administrar de manera eficiente una gran cantidad de tareas simultáneas sin consumir una gran cantidad de recursos del sistema como los subprocesos tradicionales. Aunque Spring Boot en sí no integra Project Loom, puede usar Project Loom en las aplicaciones Spring Boot para implementar rutinas. Para hacer esto, debe usar Java 17 o posterior e incluir Project Loom como una dependencia.

Aquí hay un ejemplo simple que muestra cómo usar las fibras de Project Loom para implementar rutinas:

public class CoroutineExample { 

    public static void main(String[] args) throws InterruptedException { 
        ExecutorService executorService = Executors.newVirtualThreadExecutor(); 

        SubmissionPublisher<String> editor = new SubmissionPublisher<>(executorService, 1); 

        // Suscríbete al editor 
        publisher.subscribe(new SimpleSubscriber()); 

        // Publicar algunos datos 
        para (int i = 0; i < 5; i++) { 
            publisher.submit("Data " + i); 
        } 

        // Cierra el editor y espera a que los suscriptores terminen 
        publisher.close(); 
        executorService.awaitTermination(1, Unidad de tiempo.SEGUNDOS);
        executorService.shutdown(); 
    } 
}

2. Marco de cuásar

Quasar es una biblioteca de corrutinas basada en Java que proporciona implementación y gestión de corrutinas. Con Quasar, puede crear corrutinas en aplicaciones Spring Boot para manejar tareas simultáneas.

Para usar Quasar, debe agregarlo como una dependencia a su proyecto Spring Boot. Luego, puede usar la API proporcionada por Quasar para crear, suspender y reanudar rutinas.

Aquí hay un ejemplo simple que muestra cómo usar Quasar para implementar rutinas en una aplicación Spring Boot:

@FiberSpringBootApplication 
    public class CoroutineExample { 

        public static void main(String[] args) throws InterruptedException { 
            new Fiber<Void>(() -> { 
                for (int i = 0; i < 5; i++) { 
                    System.out.println( "Data" + i); 
                    pruebe { 
                        Fiber.sleep(1000); 
                    } catch (SuspendExecution | InterruptedException e) { 
                        e.printStackTrace(); 
                    } 
                } 
            }).start().join(); 
        } 
    }

4. Integración de terceros

4.1.Vert.x

Vert.x es un marco reactivo basado en eventos que permite a los desarrolladores escribir aplicaciones asincrónicas de alto rendimiento utilizando Java u otros lenguajes JVM. Vert.x ha comenzado a intentar integrar subprocesos virtuales de Java. Actualmente hay un proyecto de incubadora de subprocesos virtuales, que incluye una implementación async/await. Este proyecto permite a los desarrolladores escribir código asíncrono usando una sintaxis similar a JavaScript o C#, sin usar devoluciones de llamada o futuros.

Vert.x es un conjunto de herramientas y un marco para crear aplicaciones escalables, con capacidad de respuesta y rendimiento. Se basa en el lenguaje Java y proporciona un modelo de programación asincrónica que permite a los desarrolladores crear fácilmente aplicaciones sin bloqueo basadas en eventos.

Características y beneficios clave:

  1. Reactivo y sin bloqueo: Vert.x emplea un bucle de eventos y un modelo de programación asincrónica que permite que las aplicaciones procesen solicitudes y eventos sin bloqueo, lo que da como resultado un alto rendimiento y una baja latencia.
  2. Soporte multilingüe: aunque Vert.x está construido en Java, también es compatible con otros lenguajes como Kotlin, Groovy y JavaScript. Esto permite a los desarrolladores escribir aplicaciones en su idioma favorito.
  3. Compatibilidad con clústeres integrada: Vert.x tiene compatibilidad con clústeres integrada para ejecutar instancias de aplicaciones en varios nodos, lo que permite el escalado horizontal y la alta disponibilidad.
  4. Componentes enriquecidos: Vert.x proporciona componentes y bibliotecas enriquecidos, incluidos el servidor HTTP, WebSocket, bus de mensajes, cliente de base de datos, etc., lo que permite a los desarrolladores crear rápidamente varios tipos de aplicaciones.
  5. Ligero: Vert.x es un marco liviano, no tan inflado como algunos marcos más grandes, y puede ejecutarse en entornos con recursos limitados.
  6. Comunidad activa: Vert.x tiene una comunidad activa de código abierto con desarrollo y actualizaciones continuos, lo que la mantiene a la vanguardia de la tecnología y tiene muchos colaboradores para respaldarla y expandirla.

Vert.x es adecuado para construir varios tipos de aplicaciones, especialmente aquellas que requieren alto rendimiento, alta concurrencia y rendimiento en tiempo real. Se puede utilizar para crear aplicaciones web, servicios API, aplicaciones de comunicación en tiempo real, aplicaciones IoT, etc. Si está interesado en la programación reactiva y el desarrollo de aplicaciones de alto rendimiento, vale la pena echarle un vistazo a Vert.x.

4.2.Embarcadero

Jetty es un servidor web Java ligero y un contenedor de servlets. Jetty también es compatible con subprocesos virtuales de Java.

Los subprocesos virtuales introducidos en Java 19 son compatibles con Jetty 12, ya que fueron compatibles con Jetty 0 y Jetty 12 a partir de 10.11.10 y 0.12.11 respectivamente.

Cuando una JVM admite subprocesos virtuales y está habilitada en Jetty (consulte Uso incorporado y Uso independiente), las aplicaciones se invocan mediante subprocesos virtuales, lo que les permite utilizar API de bloqueo simples pero con los beneficios de escalabilidad de los subprocesos virtuales.

4.3.Tomcat

Tomcat es un servidor web Java y un contenedor de servlets ampliamente utilizado. Tomcat también es compatible con subprocesos virtuales de Java y hay instrucciones relacionadas en la versión.

4.4 Helidón

Helidon es un marco de microservicio que proporciona dos modelos de programación: Helidon SE y Helidon MP. Helidon SE es un marco liviano basado en programación funcional que admite Reactive Streams y IO sin bloqueo. Helidon MP es un marco estandarizado basado en anotaciones que admite la API MicroProfile. Helidon también ha integrado subprocesos virtuales de Java y proporciona un código de muestra para mostrar cómo usarlo.

4.5.Quarkus

Quarkus es un marco completo para aplicaciones nativas de la nube, que proporciona funciones como alto rendimiento, bajo consumo de memoria, inicio rápido y recarga en caliente. Quarkus también es compatible con subprocesos virtuales de Java y proporciona documentación y guías sobre cómo usarlo.


Si el artículo es útil para usted, ¡bienvenido a prestar atención + me gusta! ! !

Supongo que te gusta

Origin blog.csdn.net/citywu123/article/details/132141035
Recomendado
Clasificación