Cruzando un erizo con un erizo: OpenJDK-11 + GraalVM

Hola Habr! A la luz de las noticias no más recientes sobre la política de Oracle con respecto a las licencias de Java, el problema de alejarse de las versiones de Oracle a OpenJDK se está volviendo cada vez más grave. Odanko en OracleLabs ha estado haciendo durante mucho tiempo una cosa genial llamada GraalVM , que es un genial compilador JIT escrito en Java, así como un tiempo de ejecución para ejecutar código en lenguajes como JavaScript, Ruby, Python, C, C ++, Scala, Kotlin, R, Clojure. Impresionante, ¿verdad? Pero no se trata de la frescura del entorno políglota, quiero decirte. Hablaremos sobre las dificultades de combinar el último conjunto de grial en el ecosistema OpenJDK 11, y un poco sobre el rendimiento, bastante ...

Primero fue la palabra


La historia de mi amistad con graalvm comenzó en el comodín en 2017. Allí, Chris Seaton habló en gran detalle sobre los componentes internos del compilador y mostró la magia de la compilación AOT utilizando la imagen nativa de la entrega del grial como ejemplo (esta es una broma que compila su código Java en un binario nativo).

Después de ese informe, entrené durante mucho tiempo en compilar el binario nativo de mi proyecto de mascota, puse muletas y rastrillos para ganar reflexión en todos los lugares (¡no está bien!) Y finalmente tropecé con problemas no resueltos con IO (algo no despegó con un cuidador del zoológico, ahora no recuerdo qué). Escupir mientras está en la imagen nativa :-(

Año 2018, todo el mismo comodín y el mismo graalvm en un informe súper detallado de Oleg Shelaev sobre AOT.

En informes y presentaciones, todo se ve tan bien, y también hay un proyecto favorito en el disco ... ¡es hora de descubrir la terminal, lanzar un nuevo candidato al lanzamiento del Grial y luchar! Tocaremos el jit.

Hola mundo


Tocando y pateando un pequeño JIT nuevo (al momento de escribir este artículo es la versión ce-1.0.0-rc14 ) usaremos un código para probar el rendimiento del sitio https://graalvm.org como ejemplo, nuestro primer ejemplo.

¿Qué proyecto de Java (incluso Hello World ) está haciendo sin ningún sistema de compilación? Así es, solo aquel en el que Java aprende a cocinar. Javak no estudiaremos para cocinar, deja que Maven dirija Javak.

Entonces conozca pom.xml:

pom.xml
<?xml version="1.0"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.mycompany.app</groupId> <artifactId>my-app</artifactId> <!--<packaging>jar</packaging>--> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>my-app</name> <url>http://maven.apache.org</url> <properties> <java.version>11</java.version> <graalvm.version>1.0.0-rc14</graalvm.version> </properties> <profiles> <profile> <id>jdk11</id> <activation> <jdk>11</jdk> </activation> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>2.10</version> <executions> <execution> <id>copy</id> <phase>process-test-classes</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <outputDirectory>${project.build.directory}/lib</outputDirectory> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> <archive> <manifest> <mainClass>com.mycompany.app.App</mainClass> </manifest> </archive> </configuration> </plugin> </plugins> </build> </profile> </profiles> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> <configuration> <release>${java.version}</release> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>org.graalvm.compiler</groupId> <artifactId>compiler</artifactId> <version>${graalvm.version}</version> </dependency> <dependency> <groupId>org.graalvm.truffle</groupId> <artifactId>truffle-api</artifactId> <version>${graalvm.version}</version> </dependency> <dependency> <groupId>org.graalvm.sdk</groupId> <artifactId>graal-sdk</artifactId> <version>${graalvm.version}</version> </dependency> <dependency> <groupId>org.graalvm.js</groupId> <artifactId>js</artifactId> <version>${graalvm.version}</version> </dependency> <dependency> <groupId>org.graalvm.js</groupId> <artifactId>js-scriptengine</artifactId> <version>${graalvm.version}</version> </dependency> </dependencies> </project> 


La estructura del archivo del proyecto se ve así:



Código de clase com.mycompany.app.App (ejemplo de copiar y pegar de graalvm.org):

App.java
  package com.mycompany.app; public class App { static final int ITERATIONS = Math.max(Integer.getInteger("iterations", 1), 1); public static void main(String[] args) { String sentence = String.join(" ", args); for (int iter = 0; iter < ITERATIONS; iter++) { if (ITERATIONS != 1) System.out.println("-- iteration " + (iter + 1) + " --"); long total = 0, start = System.currentTimeMillis(), last = start; for (int i = 1; i < 10_000_000; i++) { total += sentence.chars().filter(Character::isUpperCase).count(); if (i % 1_000_000 == 0) { long now = System.currentTimeMillis(); System.out.printf("%d (%d ms)%n", i / 1_000_000, now - last); last = now; } } System.out.printf("total: %d (%d ms)%n", total, System.currentTimeMillis() - start); } } } 


Código module-info.java :

module-info.java
  module com.mycompany.app {} 


Hmm, vacío ... Pero está vacío por la razón que quiero mostrarle cómo Java personalizado (sobre Java personalizado un poco más tarde) jurará con módulos no declarados que nuestra aplicación necesita.

El primer panqueque ...


no bultos Vamos a armar nuestro proyecto y lanzarlo. Poniéndolo de esta manera:

 mvn clean package 


Lanzamos:

 $JAVA_HOME/bin/java -XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler -Diterations=10 -jar target/my-app-1.0-SNAPSHOT.jar In 2017 I would like to run ALL languages in one VM. 

Aquí hay dos puntos importantes: JVMCI es algo experimental que ha aparecido en Java desde la versión 9, por lo que necesitamos:

  • habilitar opciones de máquina virtual experimental
      -XX: + UnlockEperimentalVMOptions 
  • habilite la máquina virtual muy experimental (a partir de las nueve, el grial está en openjdk, no en la última versión, pero aún así) - -XX: + UseJVMCICompiler

Resultado de lanzamiento
- iteración 1 - 1 (1466 ms)
2 (461 ms)
3 (463 ms)
4 (138 ms)
5 (151 ms)
6 (159 ms)
7 (266 ms)
8 (128 ms)
9 (144 ms)
total: 69999993 (3481 ms)
- iteración 2 - 1 (233 ms)
2 (169 ms)
3 (121 ms)
4 (205 ms)
5 (170 ms)
6 (152 ms)
7 (227 ms)
8 (158 ms)
9 (108 ms)
total: 69999993 (1644 ms)
- iteración 3 - 1 (98 ms)
2 (102 ms)
3 (98 ms)
4 (102 ms)
5 (95 ms)
6 (96 ms)
7 (101 ms)
8 (95 ms)
9 (97 ms)
total: 69999993 (990 ms)
- iteración 4 - 1 (109 ms)
2 (114 ms)
3 (97 ms)
4 (98 ms)
5 (100 ms)
6 (103 ms)
7 (125 ms)
8 (108 ms)
9 (100 ms)
total: 69999993 (1056 ms)
- iteración 5 - 1 (98 ms)
2 (100 ms)
3 (105 ms)
4 (97 ms)
5 (95 ms)
6 (99 ms)
7 (95 ms)
8 (123 ms)
9 (98 ms)
total: 69999993 (1010 ms)
- iteración 6 - 1 (99 ms)
2 (95 ms)
3 (102 ms)
4 (99 ms)
5 (96 ms)
6 (100 ms)
7 (99 ms)
8 (99 ms)
9 (104 ms)
total: 69999993 (993 ms)
- iteración 7 - 1 (100 ms)
2 (104 ms)
3 (95 ms)
4 (96 ms)
5 (97 ms)
6 (95 ms)
7 (94 ms)
8 (108 ms)
9 (108 ms)
total: 69999993 (1000 ms)
- iteración 8-1 (100 ms)
2 (106 ms)
3 (99 ms)
4 (95 ms)
5 (97 ms)
6 (97 ms)
7 (101 ms)
8 (99 ms)
9 (101 ms)
total: 69999993 (1012 ms)
- iteración 9-1 (105 ms)
2 (97 ms)
3 (98 ms)
4 (96 ms)
5 (99 ms)
6 (96 ms)
7 (94 ms)
8 (98 ms)
9 (105 ms)
total: 69999993 (993 ms)
- iteración 10-1 (107 ms)
2 (98 ms)
3 (99 ms)
4 (100 ms)
5 (97 ms)
6 (101 ms)
7 (98 ms)
8 (103 ms)
9 (105 ms)
total: 69999993 (1006 ms)

¿Qué vemos aquí? Y vemos que la primera iteración es la más larga (3.5 segundos), este JIT se está calentando. Y luego todo es más o menos suave (en un segundo).

Pero, ¿qué pasa si le damos a Java una versión nueva del grial? Apenas dicho que hecho:

 java -XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler -Diterations=10 --module-path=target/lib --upgrade-module-path=target/lib/compiler-1.0.0-rc14.jar -jar target/my-app-1.0-SNAPSHOT.jar In 2017 I would like to run ALL languages in one VM. 

Resultado de lanzamiento del Grial
- iteración 1 - 1 (1789 ms)
2 (547 ms)
3 (313 ms)
4 (87 ms)
5 (88 ms)
6 (87 ms)
7 (83 ms)
8 (92 ms)
9 (87 ms)
total: 69999993 (3259 ms)
- iteración 2 - 1 (241 ms)
2 (161 ms)
3 (152 ms)
4 (195 ms)
5 (136 ms)
6 (129 ms)
7 (154 ms)
8 (176 ms)
9 (109 ms)
total: 69999993 (1553 ms)
- iteración 3 - 1 (109 ms)
2 (103 ms)
3 (113 ms)
4 (172 ms)
5 (141 ms)
6 (148 ms)
7 (111 ms)
8 (102 ms)
9 (101 ms)
total: 69999993 (1211 ms)
- iteración 4 - 1 (96 ms)
2 (96 ms)
3 (104 ms)
4 (98 ms)
5 (96 ms)
6 (97 ms)
7 (98 ms)
8 (96 ms)
9 (95 ms)
total: 69999993 (972 ms)
- iteración 5 - 1 (97 ms)
2 (93 ms)
3 (99 ms)
4 (97 ms)
5 (97 ms)
6 (97 ms)
7 (95 ms)
8 (98 ms)
9 (94 ms)
total: 69999993 (965 ms)
- iteración 6 - 1 (96 ms)
2 (95 ms)
3 (96 ms)
4 (99 ms)
5 (102 ms)
6 (94 ms)
7 (99 ms)
8 (115 ms)
9 (109 ms)
total: 69999993 (1001 ms)
- iteración 7-1 (98 ms)
2 (96 ms)
3 (99 ms)
4 (98 ms)
5 (118 ms)
6 (98 ms)
7 (95 ms)
8 (99 ms)
9 (116 ms)
total: 69999993 (1017 ms)
- iteración 8-1 (95 ms)
2 (99 ms)
3 (99 ms)
4 (106 ms)
5 (101 ms)
6 (101 ms)
7 (93 ms)
8 (97 ms)
9 (108 ms)
total: 69999993 (993 ms)
- iteración 9-1 (102 ms)
2 (95 ms)
3 (97 ms)
4 (125 ms)
5 (94 ms)
6 (101 ms)
7 (100 ms)
8 (95 ms)
9 (96 ms)
total: 69999993 (1008 ms)
- iteración 10-1 (97 ms)
2 (97 ms)
3 (99 ms)
4 (112 ms)
5 (102 ms)
6 (96 ms)
7 (96 ms)
8 (98 ms)
9 (96 ms)
total: 69999993 (988 ms)

El resultado, como vemos, no es muy diferente.

Lo olvidé Bueno, no intentamos ejecutar lo mismo sin el nuevo compilador JIT. Haremos:

 java -Diterations=10 -jar target/my-app-1.0-SNAPSHOT.jar In 2017 I would like to run ALL languages in one VM. 

Resultado sin un compilador JIT novedoso
- iteración 1 - 1 (372 ms)
2 (271 ms)
3 (337 ms)
4 (391 ms)
5 (328 ms)
6 (273 ms)
7 (239 ms)
8 (271 ms)
9 (250 ms)
total: 69999993 (2978 ms)
- iteración 2 - 1 (242 ms)
2 (253 ms)
3 (253 ms)
4 (240 ms)
5 (245 ms)
6 (275 ms)
7 (273 ms)
8 (263 ms)
9 (234 ms)
total: 69999993 (2533 ms)
- iteración 3 - 1 (237 ms)
2 (235 ms)
3 (234 ms)
4 (246 ms)
5 (242 ms)
6 (238 ms)
7 (244 ms)
8 (243 ms)
9 (253 ms)
total: 69999993 (2414 ms)
- iteración 4 - 1 (244 ms)
2 (249 ms)
3 (245 ms)
4 (243 ms)
5 (232 ms)
6 (256 ms)
7 (321 ms)
8 (303 ms)
9 (249 ms)
total: 69999993 (2599 ms)
- iteración 5 - 1 (246 ms)
2 (242 ms)
3 (248 ms)
4 (256 ms)
5 (280 ms)
6 (233 ms)
7 (235 ms)
8 (266 ms)
9 (246 ms)
total: 69999993 (2511 ms)
- iteración 6 - 1 (292 ms)
2 (368 ms)
3 (339 ms)
4 (251 ms)
5 (267 ms)
6 (259 ms)
7 (289 ms)
8 (262 ms)
9 (357 ms)
total: 69999993 (3058 ms)
- iteración 7 - 1 (284 ms)
2 (258 ms)
3 (248 ms)
4 (247 ms)
5 (266 ms)
6 (247 ms)
7 (242 ms)
8 (314 ms)
9 (265 ms)
total: 69999993 (2656 ms)
- iteración 8-1 (239 ms)
2 (238 ms)
3 (257 ms)
4 (282 ms)
5 (244 ms)
6 (261 ms)
7 (253 ms)
8 (295 ms)
9 (256 ms)
total: 69999993 (2575 ms)
- iteración 9-1 (273 ms)
2 (243 ms)
3 (239 ms)
4 (240 ms)
5 (250 ms)
6 (285 ms)
7 (266 ms)
8 (285 ms)
9 (264 ms)
total: 69999993 (2617 ms)
- iteración 10-1 (245 ms)
2 (264 ms)
3 (258 ms)
4 (253 ms)
5 (239 ms)
6 (260 ms)
7 (251 ms)
8 (250 ms)
9 (256 ms)
total: 69999993 (2538 ms)

El resultado es diferente y decente.

C2 no proporciona ninguna optimización en piezas de código activas, cada iteración al mismo tiempo.

Graal puede optimizar piezas de código activas y, a la larga, ofrece un buen impulso de rendimiento.

¿Y qué?


Esta es quizás la pregunta principal que debe hacerse a sí mismo y a los demás (miembros del equipo) cuando queremos agregar una nueva característica al proyecto, una nueva herramienta, una nueva máquina virtual, un nuevo JIT ...

Mi historia, como se escribió anteriormente, comenzó con Joker 2017, luego hubo largos intentos de dominar AOT, y ahora pruebo las delicias de JIT para Java en Java.

Un proyecto favorito en el disco es una especie de motor de procesos empresariales, donde los desarrolladores de aplicaciones dibujan los procesos en la interfaz de usuario del navegador y tienen la capacidad de escribir scripts en JS que se ejecutarán en la JVM.

En futuras versiones de Java prometen eliminar nashorn, GraalVM se acerca gradualmente al lanzamiento ...

Bueno, la respuesta a la pregunta es esta:

  1. queremos un tiempo de ejecución para ejecutar JS (y no solo)
  2. quiero velocidad jit
  3. queremos que el lanzamiento de las aplicaciones de proyectos mascotas aparezca como antes en 8-ke (sin ninguna
      --module-path 
    y
      --upgrade-module-path 
    pero con un nuevo conjunto de grial)

Jlink


Los primeros dos puntos en la lista de respuestas a la pregunta anterior son lo suficientemente claros, tratemos con el último.

El hecho es que los desarrolladores-administradores-devops son perezosos y no les gusta hacer un trabajo extra (a mí también me gusta), intentan automatizar todo y empaquetarlo en un paquete listo para usar que se puede ejecutar como un simple binario. Bueno, hay un problema, solucionémoslo.

Una herramienta relativamente nueva del mundo de Java 9+ viene en nuestra ayuda, y su nombre es jlink . Estamos tratando de empaquetar nuestra aplicación con todas las bibliotecas necesarias en un paquete:

 jlink --module-path target/classes:target/lib:$JAVA_HOME/jmods --add-modules com.mycompany.app --launcher app=com.mycompany.app/com.mycompany.app.App --compress 2 --no-header-files --no-man-pages --strip-debug --output test 

Cuantos parámetros de todo tipo, describimos los principales:
  •   --module-path target / classes: target / lib: $ JAVA_HOME / jmods 
  •   --add-modules com.mycompany.app 
  •   --launcher app = com.mycompany.app / com.mycompany.app.App 
  •   - prueba de salida 

Puedes preguntarle al tío de Google sobre otros parámetros, todos ellos están destinados a reducir el tamaño total del paquete.

Veamos el resultado:



Dentro de test / bin / app hay un simple sh-script que inicia nuestra aplicación en Java que se encuentra al lado de la aplicación:

 #!/bin/sh JLINK_VM_OPTIONS="-Diterations=10" #     ,       DIR=`dirname $0` $DIR/java $JLINK_VM_OPTIONS -m com.mycompany.app/com.mycompany.app.App $@ 

Ejecute test / bin / app en C2:

 ./test/bin/app In 2017 I would like to run ALL languages in one VM. 

Resultado
- iteración 1 - 1 (315 ms)
2 (231 ms)
3 (214 ms)
4 (297 ms)
5 (257 ms)
6 (211 ms)
7 (217 ms)
8 (245 ms)
9 (222 ms)
total: 69999993 (2424 ms)
- iteración 2 - 1 (215 ms)
2 (215 ms)
3 (223 ms)
4 (224 ms)
5 (217 ms)
6 (208 ms)
7 (208 ms)
8 (222 ms)
9 (222 ms)
total: 69999993 (2164 ms)
- iteración 3 - 1 (206 ms)
2 (226 ms)
3 (234 ms)
4 (211 ms)
5 (212 ms)
6 (213 ms)
7 (210 ms)
8 (245 ms)
9 (223 ms)
total: 69999993 (2216 ms)
- iteración 4 - 1 (222 ms)
2 (233 ms)
3 (220 ms)
4 (222 ms)
5 (221 ms)
6 (219 ms)
7 (222 ms)
8 (216 ms)
9 (220 ms)
total: 69999993 (2215 ms)
- iteración 5 - 1 (231 ms)
2 (230 ms)
3 (221 ms)
4 (226 ms)
5 (227 ms)
6 (223 ms)
7 (215 ms)
8 (216 ms)
9 (219 ms)
total: 69999993 (2234 ms)
- iteración 6 - 1 (227 ms)
2 (218 ms)
3 (221 ms)
4 (254 ms)
5 (222 ms)
6 (212 ms)
7 (214 ms)
8 (222 ms)
9 (222 ms)
total: 69999993 (2241 ms)
- iteración 7 - 1 (217 ms)
2 (225 ms)
3 (222 ms)
4 (223 ms)
5 (227 ms)
6 (221 ms)
7 (219 ms)
8 (226 ms)
9 (219 ms)
total: 69999993 (2217 ms)
- iteración 8-1 (218 ms)
2 (242 ms)
3 (219 ms)
4 (218 ms)
5 (224 ms)
6 (226 ms)
7 (223 ms)
8 (220 ms)
9 (219 ms)
total: 69999993 (2228 ms)
- iteración 9-1 (234 ms)
2 (218 ms)
3 (217 ms)
4 (217 ms)
5 (225 ms)
6 (222 ms)
7 (216 ms)
8 (226 ms)
9 (214 ms)
total: 69999993 (2212 ms)
- iteración 10-1 (226 ms)
2 (230 ms)
3 (215 ms)
4 (238 ms)
5 (225 ms)
6 (218 ms)
7 (218 ms)
8 (215 ms)
9 (228 ms)
total: 69999993 (2233 ms)

Ahora en graalvm (definiendo los indicadores necesarios para ejecutar en la variable JLINK_VM_OPTIONS ):

prueba / bin / app
 #!/bin/sh JLINK_VM_OPTIONS="-XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler -Diterations=10" DIR=`dirname $0` $DIR/java $JLINK_VM_OPTIONS -m com.mycompany.app/com.mycompany.app.App $@ 


Resultado:

 Error occurred during initialization of boot layer java.lang.module.FindException: Module jdk.internal.vm.ci not found 

Bueno, hemos navegado ... Y ahora recordamos que estamos trabajando con Java 11 en un entorno modular, estamos construyendo la aplicación como un módulo, pero no le dijeron a nadie sobre los módulos utilizados. Es hora de arreglarlo.

Nueva versión de module-info.java:

 module com.mycompany.app { requires jdk.internal.vm.compiler; requires org.graalvm.sdk; requires org.graalvm.truffle; requires transitive org.graalvm.js; requires transitive org.graalvm.js.scriptengine; } 

Recopilamos , eliminamos el directorio de prueba, enlace .

Resultado:

 Error: automatic module cannot be used with jlink: icu4j from file:///home/slava/JavaProjects/graal-js-jdk11-maven-demo/target/lib/icu4j-62.1.jar 

¿Qué tipo de "módulo automático kennote bi uzd"? Y este jlink nos dice que icu4j lib no contiene module-info.class. Lo que se necesita para que tal clase aparezca dentro de la biblioteca especificada:

  • Comprenda la lista de módulos utilizados por cualquiera y cree module-info.java , defina todos los paquetes que deberían ser visibles desde el exterior
  • compile module-info.java para
  • ponga el módulo compilado-info.java en el dzharnik con cualquier

Vamos!

El archivo module-info.java con todos sus contenidos generará la utilidad jdeps de openjdk-11 para nosotros:



Compilamos module-info.java para icu4j:



Actualizamos el dzharnik introduciendo module-info.class en él:

 $JAVA_HOME/bin/jar uf target/lib/icu4j-62.1.jar -C target/modules module-info.class 

Enlace , corre .

Resultado
- iteración 1 - 1 (1216 ms)
2 (223 ms)
3 (394 ms)
4 (138 ms)
5 (116 ms)
6 (102 ms)
7 (120 ms)
8 (106 ms)
9 (110 ms)
total: 69999993 (2619 ms)
- iteración 2 - 1 (166 ms)
2 (133 ms)
3 (142 ms)
4 (157 ms)
5 (119 ms)
6 (134 ms)
7 (153 ms)
8 (95 ms)
9 (85 ms)
total: 69999993 (1269 ms)
- iteración 3 - 1 (86 ms)
2 (81 ms)
3 (87 ms)
4 (83 ms)
5 (85 ms)
6 (100 ms)
7 (87 ms)
8 (83 ms)
9 (85 ms)
total: 69999993 (887 ms)
- iteración 4 - 1 (84 ms)
2 (86 ms)
3 (88 ms)
4 (91 ms)
5 (85 ms)
6 (88 ms)
7 (87 ms)
8 (85 ms)
9 (85 ms)
total: 69999993 (864 ms)
- iteración 5 - 1 (94 ms)
2 (86 ms)
3 (84 ms)
4 (83 ms)
5 (85 ms)
6 (86 ms)
7 (84 ms)
8 (84 ms)
9 (83 ms)
total: 69999993 (854 ms)
- iteración 6 - 1 (83 ms)
2 (89 ms)
3 (87 ms)
4 (87 ms)
5 (86 ms)
6 (86 ms)
7 (91 ms)
8 (86 ms)
9 (85 ms)
total: 69999993 (865 ms)
- iteración 7-1 (87 ms)
2 (86 ms)
3 (88 ms)
4 (90 ms)
5 (91 ms)
6 (87 ms)
7 (85 ms)
8 (85 ms)
9 (86 ms)
total: 69999993 (868 ms)
- iteración 8 - 1 (84 ms)
2 (85 ms)
3 (86 ms)
4 (84 ms)
5 (84 ms)
6 (88 ms)
7 (85 ms)
8 (86 ms)
9 (86 ms)
total: 69999993 (852 ms)
- iteración 9-1 (83 ms)
2 (85 ms)
3 (84 ms)
4 (85 ms)
5 (89 ms)
6 (85 ms)
7 (88 ms)
8 (86 ms)
9 (83 ms)
total: 69999993 (850 ms)
- iteración 10-1 (83 ms)
2 (84 ms)
3 (83 ms)
4 (82 ms)
5 (85 ms)
6 (83 ms)
7 (84 ms)
8 (94 ms)
9 (93 ms)
total: 69999993 (856 ms)

Hurra! Lo hicimos! Ahora tenemos una aplicación prohibida en forma de sh-script en ejecución con nuestro Java, con todos los módulos necesarios (incluido graalvm fresco), con preferencia y señoritas.

PS


Java no se aburre y ofrece nuevos alimentos para la mente con cada lanzamiento. Pruebe nuevas funciones, experimente, comparta experiencias. Espero escribir pronto un artículo sobre cómo prohibí parte del proyecto favorito con el Grial (hay vert.x, asincronismo y scripts js, será interesante).

Y sin embargo ... este es mi primer artículo sobre Habré, - por favor, no golpeen con fuerza.

Source: https://habr.com/ru/post/445978/


All Articles