2016-07-28 30 views
1

Ich habe einen ByteArrayOuputStream, den ich von einem diff erhalten habe. Das Parsen von Java ist zu langsam, also habe ich mich entschieden, das Parsing an ein Perl-Skript zu übergeben. Ich habe ein kleines Problem damit, dass das Skript Daten von diesem Ausgabestream empfängt. Wenn ich meinen Code ausführe, hängt die Anwendung auf unbestimmte Zeit. Das ist, was ich bisher habe:Sende ByteArrayOutputStream an Perl-Skript, dann lese Antwort

public static Diff analyzeDiff(ByteArrayOutputStream baos) throws IOException { 

    ProcessBuilder pb = new ProcessBuilder(); 
    pb.command("perl/path/perl", TEMP.getAbsolutePath()); 
    Process process = pb.start(); 
    OutputStream str = process.getOutputStream(); 
    baos.writeTo(str); 
    str.flush(); 
    try { 
     process.waitFor(); 
    } catch (InterruptedException e) { 
     BufferedReader bf = new BufferedReader(new InputStreamReader(process.getInputStream())); 
     String line; 
     while ((line = bf.readLine()) != null) { 
      System.out.println(line); 
     } 
    } 

    return null; 
} 

@Test 
public void testDiffParser() throws IOException { 
    DiffParser.init(); 

    File test = new File("path/to/file/test.diff"); 

    ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
    baos.write(FileUtils.readFileToByteArray(test)); 
    //String output = baos.toString(); 
    //System.out.println(output); 

    DiffParser.analyzeDiff(baos); 
    //DiffParser.analyzeDiff(output); 
} 

Und hier ist mein Perl-Skript:

#!/usr/bin/perl 
use strict; 
use warnings; 

my $additions = 0; 
my $deletions = 0; 
my $filesChanged = 0; 

my $fileAdded = 0; 
my $line; 

foreach $line (<>) { 
    $_ = $line; 
    chomp($_); 
    print($_); 
    if (/^\-\-\-/m) { 
     $fileAdded = 1; 
    } elsif (/^\+\+\+/m && $fileAdded) { 
     $filesChanged++; 
     $fileAdded = 0; 
    } elsif (/^\+/) { 
     $additions++; 
     $fileAdded = 0; 
    } elsif (/^\-/) { 
     $deletions++; 
     $fileAdded = 0; 
    } else { 
     $fileAdded = 0; 
    } 
} 

print("$additions $deletions $filesChanged\n") 

Gibt es einen Weg, um tatsächlich zu tun, was ich tun möchte?

Edit: Dies ist, wie ich es in Java tat:

private Diff parseDiff(final ByteArrayOutputStream baos) { 

    final Diff diff = new Diff(); 

    int filesChanged = 0; 
    int additions = 0; 
    int deletions = 0; 

    boolean fileAdded = false; 

    final String[] lines = baos.toString().split("\n"); 

    for (final String line : lines) { 

     if (line.startsWith("---")) { 
      fileAdded = true; 
     } else if (line.startsWith("+++") && fileAdded) { 
      filesChanged++; 
      fileAdded = false; 
     } else if (line.startsWith("+")) { 
      additions++; 
      fileAdded = false; 
     } else if (line.startsWith("-")) { 
      deletions++; 
      fileAdded = false; 
     } else { 
      fileAdded = false; 
     } 

    } 

    diff.additions = additions; 
    diff.deletions = deletions; 
    diff.changedFiles = filesChanged; 

    return diff; 
} 

Edit 2 Wenn Sie etwas Kontext möchten, können Sie auf diese verweisen Related question

+0

'Java's Parsing ist zu langsam 'Die Übergabe an Perl wäre nicht meine erste Wahl (fügt eine zusätzliche Abhängigkeit/Fehlerpunkt hinzu) - in Betracht ziehen, den Java-Parsing-Code zu posten, da es möglicherweise Möglichkeiten gibt, ihn zu optimieren – copeg

+0

@ Copeg sicher, habe hinzugefügt, dass per Vorschlag – Himself12794

+0

Ich denke Multithreading diesen Code wäre eine bessere und schnellere Idee als die Übergabe an einen anderen Prozess ...? – saml

Antwort

1

ich benutze eine Tablette zur Zeit, so kann ich nicht viel helfen, aber Ihre Perl braucht etwas Arbeit.

Sie sollten for $line (<>) nicht verwenden, da versucht wird, alle der Eingabe in eine Liste zu lesen, bevor Sie zu iterieren beginnen. Sie verwenden auch nicht $line so sollten Sie direkt in $_ mit

while (<>) { ... } 

Es gibt auch keine Notwendigkeit, chomp jede Zeile gelesen, und ich verstehe nicht, warum Sie print für jeden Datensatz rufen Sie? Es ist nach der chomp, so dass die Ausgabe eine Kopie der Eingabe auf einer sehr langen Zeile mit den Aggregatwerten am Ende sein wird.

Ich vermute, das Perl-Skript empfängt die Daten gut, aber Probleme mit der Eingabe aller Eingabe in den Speicher gleichzeitig mit einer zweiten Kopie von allem als Ausgabe!

+0

Ich gestehe, vor heute hatte ich noch nie etwas in Perl geschrieben. Dies ist hauptsächlich ein Ergebnis des Kopierens meines Java-Codes und des Modifizierens zum Ausführen. – Himself12794

+0

@ Himself12794: Ich bin froh zu helfen, aber wenn Ihr Java-Code auch versucht, den gesamten Stream zwischenzuspeichern, wie [Vladimír Schäfer sagt] (http://stackoverflow.com/a/38652955/622310) dann bist du in Schwierigkeiten. Ich habe nur wenige Java-Kenntnisse, deshalb kann ich nicht anders, aber ich kann mir vorstellen, dass es eine Möglichkeit gibt, einen Stream zu lesen und ihn inkrementell an den Perl-Child-Prozess zu übergeben. Perl wird sicherlich verpflichtet sein. – Borodin

0

Mit ByteArrayOutputStream bedeutet, dass das gesamte Ergebnis des diff auf einmal gespeichert werden muss, anstatt verarbeitet und Müll in Blöcken gesammelt werden. Ihr Java-Programm war möglicherweise langsam, weil nicht genügend Speicher zur Verfügung stand und die Garbage-Collection ständig ausgeführt wurde.

Java wird viel schneller bei jeder Aufgabe, die Sie werfen, verglichen mit Perl. Es ist eine Just-in-Time-kompilierte Sprache, im Gegensatz zu einer interpretierten Sprache im Fall von Perl. Siehe z.B. http://blog.carlesmateo.com/2014/10/13/performance-of-several-languages/, https://attractivechaos.github.io/plb/ oder https://en.wikipedia.org/wiki/Java_performance (im Vergleich zu anderen Sprachen).

Wenn Sie Leistung benötigen, sollten Sie Ihren Java-Code optimieren, anstatt eine Abhängigkeit von Perl zu erstellen.

+0

Leider ist das das Format, in dem ich die Daten erhalte. – Himself12794

+0

Tribalism ist hier nicht willkommen. *** "Java wird viel schneller bei jeder Aufgabe sein, die Sie ihm gegenüber werfen, im Vergleich zu Perl" *** Das erfordert ein Zitat. Ich glaube, du redest Unsinn. Die Hauptgründe für den Einsatz von Java waren immer seine plattformübergreifende Leistung und seine Open-Source-Ursprünge, und [Oracle ändert das] (http://arstechnica.com/information-technology/2016/07/how-oracles-business) -als-üblich-ist-bedrohlich-zu-kill-java /). Darüber hinaus wird es aufgrund seiner Abstraktionsstärke je nach Aufgabenstellung mehr oder weniger effizient als Perl sein. Seine Forderungen nach formaler Typisierung machen es weniger populär. – Borodin

+0

Überprüfen Sie die obigen Benchmarks und werfen Sie auf die Erfahrung in der Verarbeitung von Milliarden von Datensätzen pro Tag auf beiden Plattformen. –