[JAVA] Ich habe versucht, was ich mit Stream leise versuchen wollte.

Es ist in Ordnung, irgendwie am Adventskalender teilzunehmen, aber ich habe nichts zu schreiben, also werde ich über Stream sprechen, den ich schreiben kann. Der Code, den ich dieses Mal ausprobiert habe, ist auch in GitHub gespeichert.

Lesbarkeitsaspekt

Dieser Typ hat in Java 8 hinzugefügt. Wie viele von Ihnen vielleicht bereits wissen, ist die Ausführungszeit langsamer als der prozedurale Typ, wenn Sie versuchen, die Ausführungszeit zu bewerten und zu messen. Wenn die zu behandelnden Elemente klein sind. Der Vorteil ist, dass der Methodenname klar ist und leicht zu verstehen ist, was die Quelle tun möchte.

Einfache Benchmark-Ausführungsumgebung

Ich möchte keine Tools verwenden oder die Häufigkeit mit 1 Million vergleichen Es scheint, dass Sie nanoTime verwenden können, aber ich habe mich für currentTimeMillis entschieden, weil ich nur den Unterschied kennen muss.

Bench.java


public class Main {
    public static void main(String[] args) {
        System.out.println("Excution time:"+benchMark()+"[sec]");
    }

    private static double benchMark(){
        long start = System.currentTimeMillis();
        HogeSomeTask task = new HogeSomeTask();
        task.something_do();
        long end = System.currentTimeMillis();

        return ((end - start) / 1000.0);
    }
}

OS:Ubuntu 16.04 CPU: Intel Core i7-2700K CPU bei 5,9 GHz (Bitte verzeihen Sie die alte) JDK:Open-jdk9

Beispielcode

Der folgende Code ist das Ergebnis eines Benchmarking mit dem Code des Prozesses, um die Zieldaten mit weniger als 5 Zeichen als Bedingung auszugeben. Im Gegenteil, ich habe auch versucht, Daten mit 5 oder mehr Zeichen auszugeben, aber das Ergebnis war fast das gleiche, also habe ich es weggelassen.

Procedural.java


    public void use_for(){ 
        List<String>list = Arrays.asList("Java","Ruby","Csharp","Scala","Haskell");
        for(String lang : list){
            if(lang.length() < 5){
                System.out.println(lang);
            }
        }
    } 

Die durchschnittliche Ausführungszeit für 10 Mal beträgt 0,001 [Sek.]. Sehr schnell

Verwenden Sie Stream

Stream.java


 public void use_stream(){ 
        List<String>list = Arrays.asList("Java","Ruby","Csharp","Scala","Haskell");
        list.stream().filter(lang -> lang.length() < 5).forEach(System.out::println);
 }

Die durchschnittliche Ausführungszeit für 10 Mal beträgt 0,025 [Sek.]. Es ist etwas langsamer als der prozedurale Typ.

Mit Java9 verfügt Stream auch über neue Funktionen

Es fühlt sich jetzt eher so an, aber werfen wir einen kurzen Blick auf die Methode. Es kann wie Scala mit der Methode take / dropWhile geschrieben werden. takeWhile Eine Methode, die Zieldaten verarbeiten kann (während die Bedingungen erfüllt sind), indem einfach die Zielbedingungen angegeben werden. Die Zwischenverarbeitung wurde reduziert.

takeWhileExample.java


   List<String>list = Arrays.asList("Java","Ruby","Csharp","Scala","Haskell")   
         list.stream().takeWhile(lang -> lang.length() < 5).forEach(System.out::println);

dropWhile Eine Methode, die Zieldaten (nachdem die Bedingungen abgeglichen wurden) einfach durch Angabe der Zielbedingungen ausgeben kann. Wie bei takeWhile wurde die Zwischenverarbeitung reduziert.

dropWhileExample.java


  List<String> list = Arrays.asList("Java","Ruby","Csharp","Scala","Haskell");
        list.stream().dropWhile(lang -> lang.length() < 5).forEach(System.out::println);

ofNullable Wenn die Zieldaten nicht null sind, wird ein Stream zurückgegeben. Wenn null, eine Methode, die einen leeren Stream zurückgibt. Sie können jetzt Streams direkt aus Optional schreiben, wie unten gezeigt

optional.java


Optional.ofNullable(null).stream().forEach(System.out::println);

Die Geschwindigkeit, die Ihnen wichtig ist

Ich habe alles ausprobiert und es verglichen, also habe ich es in einer Tabelle zusammengefasst. In Bezug auf ofNullable scheint es einen großen Punkt zu geben, Null sicher zu behandeln. Dieses Mal überprüfe ich die Leistung beim Umgang mit Daten. Ich werde es weglassen, da ich keine Zeit für die Anzeigenpflege habe.

1. Verarbeitung des obigen Beispielcodes

Durchschnittliche Ausführungszeit(10 mal)
Verfahrensart 0.001[sec]
Stream 0.025[sec]
parallelStream 0.026[sec]
takeWhile 0.026[sec]
takeWhile(Verwenden Sie parallelStream) 0.032[sec]

Es gibt keinen großen Unterschied zu einigen Methoden aus Java8. Die Zwischenverarbeitung scheint langsam zu sein

2. Umgekehrte Verarbeitung von 1

Durchschnittliche Ausführungszeit(10 mal)
Verfahrensart 0.001[sec]
Stream 0.023[sec]
parallelStream 0.031[sec]
dropWhile 0.024[sec]
dropWhile(Verwenden Sie parellelStream) 0.028[sec]

Das gleiche wie oben

Gründe, gegen den Prozedurtyp zu verlieren

Grob gesagt wird beim prozeduralen Typ die Verarbeitung fast so ausgeschrieben wie sie ist und mit jdk kompiliert. Selbst wenn die Daten einfach sind, scheint der Stream, der die Zwischenverarbeitung durchführt, langsam zu sein.

Ergänzung

Ich möchte die Gründe für Verspätung klären. Zu diesem Zweck habe ich versucht, den in der Stream-Methode geschriebenen Prozess mit der Funktion von IntelliJ zu verfolgen. Es ist in kleine Methodenaufrufe unterteilt, und der Mechanismus wie die verzögerte Ausführung wird verlangsamt.

Gibt es eine Zeit, in der Stream schnell ist?

Wenn Sie es schreiben möchten, müssen Sie nur Stream auswählen, der leicht zu lesen ist, und selbst wenn es langsam ist, ist der Unterschied nicht so groß. In Bezug auf die Leistung habe ich es jedoch versucht, da es effektiv zu sein scheint, wenn die zu behandelnden Elemente groß sind.

Bedingungen

Erstellen Sie als Testdaten 1 Million Elemente einer zufälligen Zeichenfolge, die aus 20 Buchstaben mit Großbuchstaben und Zahlen besteht.

BigData.java


Random r = new Random(2111);
List<String> data = range(0, 1_000_000)
    .mapToObj(i->
        r.ints().limit(20)
            .map(n -> Math.abs(n) % 36)
            .map(code -> (code < 10) ? '0' + code : 'A' + code - 10)
            .mapToObj(ch -> String.valueOf((char)ch))
            .toString())
    .collect(toList());

Aus diesem Element werden nur die Zahlen extrahiert, und die Summe beträgt 30 oder weniger.

Verfahrensprobe

Procedural.java


  public static long use_for(List<String> data){
        long result = 0;
        for(String d : data){
            String numOnly = d.replaceAll("[^0-9]", "");
            if(numOnly.isEmpty()) continue;
            int total = 0;
            for(char ch : numOnly.toCharArray()){
                total += ch - '0';
            }
            if(total >= 30) continue;
            long value = Long.parseLong(numOnly);
            result += value;
        }
        return result;
    }

Beispiel streamen

Stream.java


 public static long streamSum(List<String>data){
        return data.stream()
                .map(d -> d.replaceAll("[^0-9]", ""))
                .filter(d -> !d.isEmpty())
                .filter(d -> d.chars().map(ch -> ch - '0').sum() < 30)
                .mapToLong(d -> Long.parseLong(d)).sum();
 }

Versuchen Sie auch takeWhile / dropWhile

Ich bin gespannt, wie es mit nur Stream und ParallelStream verglichen wird, also werde ich es versuchen.

takeWhileSample.java


  public static long takeWhileSum(List<String> data){
        return data.stream()
                .map(d -> d.replaceAll("[^0-9]", ""))//Nicht-Nummern entfernen
                .takeWhile(d -> !d.isEmpty())
                .takeWhile(d -> d.chars().map(ch -> ch - '0').sum() < 30)//Die Summe der Zahlen beträgt weniger als 30
                .mapToLong(d -> Long.parseLong(d)).sum();
  }

dropWhileSample


    public static long dropWhileSum(List<String> data){
        return data.stream()
                .map(d -> d.replaceAll("[^0-9]", ""))
                .dropWhile(d -> d.isEmpty())
                .dropWhile(d -> d.chars().map(ch -> ch - '0').sum() > 30)
                .mapToLong(d -> Long.parseLong(d)).sum();
   }

Benchmark-Ergebnisse

Durchschnittliche Ausführungszeit(10 mal)
Verfahrensart 2.132[sec]
parallelStream 1.321[sec]
Stream 2.107[sec]
takeWhile 0.457[sec]
takeWhile(parallelStream) 1.325[sec]
dropWhile 2.175[sec]
dropWhile(parallelStream) 1.377[sec]

Ich habe das Gefühl, endlich den wahren Wert gesehen zu haben. takeWhile ist bei weitem das schnellste. Das dropWhile war ungefähr das gleiche wie der prozedurale Typ, aber das Aufrufen von einem parallelStream machte es viel besser.

Fazit

das ist alles. Es war eine gute Gelegenheit, das auszuprobieren, woran ich interessiert war.

Artikel, auf die verwiesen wird

Zweck von Java 8 Stream, einfache Schreibbarkeit, Lesbarkeit und Auswirkung der Parallelverarbeitung Messen Sie das Ausführungsergebnis des Programms mit C ++, Java, Python.

Eine solche.

Recommended Posts

Ich habe versucht, was ich mit Stream leise versuchen wollte.
Ich habe versucht, mit Java zu interagieren
Ich habe versucht, mit Web Assembly zu beginnen
Ich habe versucht, die Stream-API zusammenzufassen
Was ist Docker? Ich habe versucht zusammenzufassen
Ich habe versucht, AdoptOpenJDK 11 (11.0.2) mit dem Docker-Image zu überprüfen
Ich habe versucht, eine Standardauthentifizierung mit Java durchzuführen
Ich habe versucht, die Federbeinkonfiguration mit Coggle zu verwalten
Ich habe versucht, Anmeldeinformationen mit JMX zu verwalten
Ich wollte Spring Boot in einem Multiprojekt gradle
Ich habe versucht, den Block mit Java zu brechen (1)
Was ich versucht habe, als ich alle Felder einer Bohne bekommen wollte
Ich habe versucht, das Hochladen von Dateien mit Spring MVC zu implementieren
Ich habe versucht, CSV mit Outsystems zu lesen und auszugeben
Ich habe versucht, TCP / IP + BIO mit JAVA zu implementieren
[Java 11] Ich habe versucht, Java auszuführen, ohne mit Javac zu kompilieren
Ich habe MySQL 5.7 mit Docker-Compose gestartet und versucht, eine Verbindung herzustellen
Ich habe versucht, mit Spring Data JPA zu beginnen
Ich habe versucht, Animationen mit der Blazor + Canvas-API zu zeichnen
Ich habe versucht, Sterling Sort mit Java Collector zu implementieren
Ich habe versucht herauszufinden, was sich in Java 9 geändert hat
Ich habe DI mit Ruby versucht
Ich habe versucht, node-jt400 (SQL-Stream)
Ich habe UPSERT mit PostgreSQL ausprobiert.
Ich habe BIND mit Docker ausprobiert
Ich habe versucht, yum-cron zu verifizieren
Ich habe versucht, mit Chocolatey eine Java8-Entwicklungsumgebung zu erstellen
Ich habe versucht, eine Java EE-Anwendung mit OpenShift zu modernisieren.
Ich habe versucht, die Verarbeitungsgeschwindigkeit mit spiritueller Technik zu erhöhen
[Rails] Ich habe versucht, eine Mini-App mit FullCalendar zu erstellen
Ich habe versucht, den Chat mit dem Minecraft-Server mit der Discord-API zu verknüpfen
[Rails] Ich habe versucht, die Stapelverarbeitung mit der Rake-Task zu implementieren
Was ich mit der Redmine REST API süchtig gemacht habe
Ich habe versucht, mit Docker eine Padrino-Entwicklungsumgebung zu erstellen
Ich habe versucht, mit Swagger mit Spring Boot zu beginnen
Ich habe versucht, mit Ractor mehrere Objekte übergeben zu können
Ich habe versucht, das Problem der "mehrstufigen Auswahl" mit Ruby zu lösen
Ich habe versucht, C # (Indexer) zu kauen.
Ich habe versucht zusammenzufassen, was bei der Site-Java-Ausgabe gefragt wurde.
Ich habe versucht, JOOQ mit Gradle zu verwenden
Ich habe eine morphologische Analyse mit MeCab versucht
Ich habe versucht, mit Docker eine Plant UML Server-Umgebung zu erstellen
Ich habe versucht, mithilfe von JDBC Template mit Spring MVC eine Verbindung zu MySQL herzustellen
Ich habe versucht, die Unterstützung für iOS 14 zusammenzufassen
Ich habe versucht, die Bildvorschau mit Rails / jQuery zu implementieren
Ich habe versucht, mit Eclipse + Tomcat eine http2-Entwicklungsumgebung zu erstellen
Ich habe versucht, eine flexible ODER-Zuordnung mit MyBatis Dynamic SQL zu implementieren
Ich habe versucht, UDP mit Java zu kommunizieren
Ich habe versucht, die Methode zu erklären
Wovon ich süchtig war, als ich die Google-Authentifizierung mit Rails implementierte
Ich habe versucht, Ruby's Float (arg, Ausnahme: true) mit Builtin neu zu implementieren