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.
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.
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
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
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.
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);
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.
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
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
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.
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.
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.
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.
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;
}
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();
}
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();
}
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.
das ist alles. Es war eine gute Gelegenheit, das auszuprobieren, woran ich interessiert war.
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