[JAVA] Führen Sie Scala mit GraalVM aus und machen Sie es zu einem nativen Image

Führen Sie GraalVM aus der Sicht eines Scala-Programmierers ein und verwenden Sie es.

GraalVM?

GraalVM scheint (manchmal) in der Lage zu sein, Scala (Java) -Programme zu beschleunigen, wenn Sie den Sprung wagen.

Wenn Sie diesen Bereich lesen, wird er etwas detaillierter geschrieben. https://www.graalvm.org/docs/why-graal/#for-java-programs

Kurz zusammengefasst sind die Funktionen

  1. Beschleunigen Sie Java Es wird gesagt, dass es einige Verbesserungen bei der JIT-Kompilierung gibt.
  2. Führen Sie eine andere Sprache (JS oder Python) im Java-Kontext aus Kann Polyglot-Anwendungen entwickeln
  3. Erstellen Sie ein natives Bild AOT-Kompilierung anstelle von JIT

Drei Punkte sind aufgelistet.

In diesem Artikel werde ich auf 1 und 3 eingehen. Siehe Sprachen mit der Graal Polyglot-API einbetten für 2.

Die Version von GraalVM ist CE-1.0.0-rc9.

Installation

Da es auf Github hochgeladen wurde, laden Sie es herunter und entpacken Sie es. [Releases · oracle/graal](https://github.com/oracle/graal/releases

$ wget https://github.com/oracle/graal/releases/download/vm-1.0.0-rc9/graalvm-ce-1.0.0-rc9-macos-amd64.tar.gz 
$ tar zxvf graalvm-ce-1.0.0-rc9-macos-amd64.tar.gz
$ export GRAALVM_HOME=$PWD/graalvm-ce-1.0.0-rc9

Zusätzlich wird eine Umgebungsvariable namens "GRAALVM_HOME" gesetzt.

Beschleunigen Sie Ihr Programm mit GraalVM

Es ist sehr einfach zu bedienen, einfach installieren und anstelle von Java verwenden.

$ java -jar main.jar #Führen Sie mit Oracle JDK aus
$ $GRAALVM_HOME/bin/java -jar main.jar #Auf Graal VM ausführen

Verwenden Sie sbt-jmh, um die Leistung zu überprüfen und festzustellen, ob dies allein wirklich beschleunigt. Der Code für die Leistungsüberprüfung wird anhand der offiziellen Graal VM-Demos: Graal Performance-Beispiele für Java anhand der Zeichenfolge gezählt. Ich habe es versucht. Beispielcode finden Sie unter Github.

package net.petitviolet.example

import org.openjdk.jmh.annotations._

@State(Scope.Thread)
class ForBench {
  private val sentence = "In 2017 I would like to run ALL languages in one VM."
  private val answer = 7

  @Benchmark
  @BenchmarkMode(Array(Mode.Throughput))
  def bench_upperCaseCount() = {
    upperCaseCount(sentence)
  }

  private def upperCaseCount(args: String) = {
    val sentence = String.join(" ", args)
    require(sentence.filter(Character.isUpperCase).length == answer)
  }
}

Führen Sie jmh für diesen Code aus. Optional können Sie -jvm an die Task jmh: run übergeben. Versuchen Sie also, den Benchmark während des Wechsels auszuführen.

Zunächst Oracle JDK 1.8.0_192. Die resultierende Ausgabe wird entsprechend ausgedünnt.

sbt:main> jmh:run -i 10 -wi 10 -f1 -t 1 -jvm /path/to/java/1.8/bin/java
[info] Running (fork) org.openjdk.jmh.Main -i 10 -wi 10 -f1 -t 1 -jvm /path/to/java/1.8/bin/java
[info] # JMH version: 1.21
[info] # VM version: JDK 1.8.0_192, Java HotSpot(TM) 64-Bit Server VM, 25.192-b12
[info] # VM invoker: /path/to/java/1.8/bin/java
[info] # Benchmark mode: Throughput, ops/time
[info] # Benchmark: net.petitviolet.example.ForBench.bench_upperCaseCount
[info] Benchmark                       Mode  Cnt        Score        Error  Units
[info] ForBench.bench_upperCaseCount  thrpt   10  2548794.689 ± 212771.778  ops/s

Führen Sie dann GraalVM 1.0.0-rc9 aus.

sbt:main> jmh:run -i 10 -wi 10 -f1 -t 1 -jvm /path/to/graalvm-ce-1.0.0-rc9/Contents/Home/bin/java
[info] Running (fork) org.openjdk.jmh.Main -i 10 -wi 10 -f1 -t 1 -jvm /path/to/graalvm-ce-1.0.0-rc9/Contents/Home/bin/java
[info] # JMH version: 1.21
[info] # VM version: JDK 1.8.0_192, GraalVM 1.0.0-rc9, 25.192-b12-jvmci-0.49
[info] # *** WARNING: JMH support for this VM is experimental. Be extra careful with the produced data.
[info] # Benchmark mode: Throughput, ops/time
[info] # Benchmark: net.petitviolet.example.ForBench.bench_upperCaseCount
[info] # Run progress: 0.00% complete, ETA 00:03:20
[info] Benchmark                       Mode  Cnt        Score       Error  Units
[info] ForBench.bench_upperCaseCount  thrpt   10  2904523.828 ± 28572.650  ops/s
[success] Total time: 203 s, completed Nov 25, 2018 9:46:55 PM

Beim einfachen Vergleich der Ergebnisse war GraalVM etwas schneller.

Ergebnis OracleJDK GraalVM
Throughput 2548794.689 2904523.828

Das heißt, diesmal ist es ein einfacher Code, daher ist es möglich, dass GraalVM vorteilhafter ist, aber zumindest gibt es Fälle, in denen die Verwendung von GraalVM nur so schneller ist.

NativeImage

Anstelle der JIT-Kompilierung wird dann die AOT-Kompilierung verwendet, um nativen Code, dh ausführbare Binärdateien, auszuspucken. SubstrateVM ist die Technologie, die dies unterstützt.

Substrate VM is a framework that allows ahead-of-time (AOT) compilation of Java applications under closed-world assumption into executable images or shared objects (ELF-64 or 64-bit Mach-O).

Es gibt Scala Native in Scala, aber ich werde es hier nicht erwähnen.

Machen Sie zuerst "native-image" nutzbar. Wenn Sie es jedoch bereits heruntergeladen haben, können Sie es einfach in Ihren PFAD einfügen.

$ export PATH=$PATH:$GRAALVM_HOME/Contents/Home/bin
$ native-image --version
GraalVM Version 1.0.0-rc9

Es kann verwendet werden, um Scala (Java) -Programme in nativen Code zu konvertieren. Insbesondere können Sie dem Argument des Befehls "native-image" fat-JAR geben. Wenn Sie sbt verwenden, können Sie mit sbt-Assembly problemlos Fat-JAR generieren, sodass Sie es verwenden können.

Geben Sie den folgenden Befehl ein, um es auszuführen.

$ native-image \
  -jar main.jar \ # sbt-Bei der Montage wird Fett ausgespuckt-Geben Sie JAR an
  -H:IncludeResources=".*.xml|.*.conf" \
  -H:+ReportUnsupportedElementsAtRuntime \
  -H:Name=app \ #Binärpfad ausgeben
  --verbose

Geben Sie für das Argument von -jar die Fat-JAR an, die von sbt-Assembly ausgespuckt wird. Mit -H: IncludeResources können Sie die Ressourcendatei, die in die Binärdatei aufgenommen werden soll, mit einem regulären Ausdruck angeben. Dieses Mal wollte ich logback.xml und application.conf einschließen, also habe ich es angegeben.

Übrigens, wenn Sie "-cp" anstelle von "-jar" verwenden, können Sie dies ohne Fett-JAR tun, aber es wird empfohlen, weil es weniger einprägsam ist. Siehe Bilderzeugungsoptionen, da andere Befehle optional sind.

Was passiert, wenn Sie mit NativeImage konvertieren?

Was mich glücklich macht, ein Eingeborener zu sein, ist, dass das Startup explosiv ist. Java verbessert das starke Hochfahren von JVM ohnehin dramatisch.

Der in diesem Beispiel ausgeführte Quellcode lautet [scala_graalvm_prac / Application.scala](https://github.com/petitviolet/scala_graalvm_prac/blob/adad5c144534d473e5b61de38ec5e86f6d809172/modules/main/src/net/ Ich verwende die in scala) und es ist eine Anwendung, die gerade eine Webanwendung startet und beendet, die [http4s] verwendet (https://github.com/http4s/http4s).

Versuchen Sie zunächst, es zum Vergleich als Java auszuführen.

$ /usr/bin/time java -jar main.jar TimeTest
2018-11-26 17:24:29.129 INFO  [main][o.h.b.c.n.NIO1SocketServerGroup] - Service bound to address /0:0:0:0:0:0:0:0:8080
2018-11-26 17:24:29.135 INFO  [main][o.h.s.b.BlazeBuilder] -   _   _   _        _ _
2018-11-26 17:24:29.135 INFO  [main][o.h.s.b.BlazeBuilder] -  | |_| |_| |_ _ __| | | ___
2018-11-26 17:24:29.135 INFO  [main][o.h.s.b.BlazeBuilder] -  | ' \  _|  _| '_ \_  _(_-<
2018-11-26 17:24:29.135 INFO  [main][o.h.s.b.BlazeBuilder] -  |_||_\__|\__| .__/ |_|/__/
2018-11-26 17:24:29.135 INFO  [main][o.h.s.b.BlazeBuilder] -              |_|
2018-11-26 17:24:29.230 INFO  [main][o.h.s.b.BlazeBuilder] - http4s v0.18.9 on blaze v0.12.13 started at http://[0:0:0:0:0:0:0:0]:8080/
2018-11-26 17:24:29.230 INFO  [main][n.p.e.Application] - start server.
2018-11-26 17:24:29.230 INFO  [main][n.p.e.Application] - start shutting down immediately.
2018-11-26 17:24:29.235 INFO  [main][o.h.b.c.ServerChannel] - Closing NIO1 channel /0:0:0:0:0:0:0:0:8080 at Mon Nov 26 17:24:29 JST 2018
2018-11-26 17:24:29.237 INFO  [main][o.h.b.c.n.NIO1SocketServerGroup] - Closing NIO1SocketServerGroup
2018-11-26 17:24:29.237 INFO  [main][n.p.e.Application] - shutting down completed.
        1.74 real         1.84 user         0.20 sys

Das Ergebnis.

Versuchen Sie als Nächstes, die mit native-image erstellte Binärdatei auszuführen.

$ /usr/bin/time ./app TimeTest
2018-11-26 17:24:37.190 INFO  [main][o.h.b.c.n.NIO1SocketServerGroup] - Service bound to address /0:0:0:0:0:0:0:0:8080
2018-11-26 17:24:37.190 INFO  [main][o.h.s.b.BlazeBuilder] -   _   _   _        _ _
2018-11-26 17:24:37.190 INFO  [main][o.h.s.b.BlazeBuilder] -  | |_| |_| |_ _ __| | | ___
2018-11-26 17:24:37.190 INFO  [main][o.h.s.b.BlazeBuilder] -  | ' \  _|  _| '_ \_  _(_-<
2018-11-26 17:24:37.190 INFO  [main][o.h.s.b.BlazeBuilder] -  |_||_\__|\__| .__/ |_|/__/
2018-11-26 17:24:37.190 INFO  [main][o.h.s.b.BlazeBuilder] -              |_|
2018-11-26 17:24:37.190 INFO  [main][o.h.s.b.BlazeBuilder] - http4s v0.18.9 on blaze v0.12.13 started at http://[0:0:0:0:0:0:0:0]:8080/
2018-11-26 17:24:37.190 INFO  [main][n.p.e.Application] - start server.
2018-11-26 17:24:37.190 INFO  [main][n.p.e.Application] - start shutting down immediately.
2018-11-26 17:24:37.190 INFO  [main][o.h.b.c.ServerChannel] - Closing NIO1 channel /0:0:0:0:0:0:0:0:8080 at Mon Nov 26 17:24:37 JST 2018
2018-11-26 17:24:37.190 INFO  [main][o.h.b.c.n.NIO1SocketServerGroup] - Closing NIO1SocketServerGroup
2018-11-26 17:24:37.190 INFO  [main][n.p.e.Application] - shutting down completed.
        0.03 real         0.01 user         0.01 sys

An der Ausgabe der Anwendung hat sich fast nichts geändert. Da es sich jedoch um 1,74 Sekunden → 0,03 Sekunden handelt, ist der Start deutlich schneller.

Andere verschiedene Gefühle

Es wird gesagt, dass Twitter in Produktion gegangen ist, aber es kann möglich sein, es zu übernehmen, abhängig vom Ergebnis der Betriebs- / Leistungsüberprüfung. Ein weiterer Vorteil ist, dass die Rückgabe auch bei Problemen problemlos möglich ist.

Es ist jedoch noch zu früh, eine native Codierung mit "native-image" einzuführen.

Die Einschränkungen sind in LIMITATIONS.md beschrieben. Die große Sache ist, dass das Laden dynamischer Klassen nicht unterstützt wird und einige Reflexionen nicht verfügbar sind. Scala verwendet oft Makros, aber es funktioniert oft nicht. Aus diesem Grund konnte ich Playframework oder Akka-HTTP nicht verwenden. Es gibt immer noch viele Einschränkungen, z. B. wenn Sie versuchen, den asynchronen Appender von Logback anders als das Webanwendungsframework zu verwenden, funktioniert dies nicht gut. Da AOT nur vorkompiliert ist, ist es schwierig geworden, dies zur Laufzeit zu tun. Übrigens gab es eine GraalVM-Demo, die den Scala-Compiler in ein natives Image konvertierte. Vielleicht möchten Sie auch darauf verweisen. graalvm-demos/scala-days-2018/scalac-native at master · graalvm/graalvm-demos

Dies bedeutet jedoch nicht, dass es überhaupt verwendet werden kann. Beispielsweise kann es eine Option sein, Tools für CLI mit Scala (Java) + native-image anstelle von Golang zu betreiben.

Wenn es vielseitiger wird, besteht die Möglichkeit, dass die Inkompatibilität zwischen der Docker / Kubernetes-Ära und dem JVM-Spin-up verbessert wird. Ich würde es daher gerne in Zukunft erwarten.

Recommended Posts

Führen Sie Scala mit GraalVM aus und machen Sie es zu einem nativen Image
Versuchen Sie, Java mit GraalVM in ein natives Modul zu integrieren
[Java] Mach es konstant
Machen Sie mit Ruby2D ein Labyrinth
Erstellen Sie mit JavaFX ein Diashow-Tool
Priority Queue max Machen Sie es zu einer Warteschlange
Machen Sie eine Müllabfuhr mit line-bot-sdk-java
Erstellen Sie eine Listenkarte mit LazyMap
Lassen Sie Jupyter Lab überall mit Docker arbeiten
Machen Sie ein Tippspiel mit Ruby
Machen wir eine Weihnachtskarte mit Verarbeitung!
Erstellen Sie mit Sinatra eine Familien-ToDo-Liste
Erstellen Sie mit Sinatra eine Familien-ToDo-Liste
Führen Sie DMN mit der Camunda DMN Engine aus
Erstellen Sie trotzdem eine Anmeldefunktion mit Rails
[Docker] [Nginx] Erstellen Sie mit Nginx eine einfache ALB
Führen Sie Rust von Java mit JNA (Java Native Access) aus.
Führen Sie die Scala-Anwendung mit Spring Boot über Gradle aus
Erstellen Sie Scala Seq aus Java, machen Sie Scala Seq zu einer Java-Liste
Lassen Sie uns eine Suchfunktion mit Rails (Ransack) machen
Machen Sie System.out Mock mit dem Spock Test Framework