2017-01-16 3 views
2

Ich bin parallelisieren ein recht komplexes Programm, um es schneller zu bekommen. Dafür nutze ich die meiste Zeit die ExecutorService. Bis jetzt funktionierte es ziemlich gut, aber dann bemerkte ich, dass nur eine Codezeile mein Programm halb so schnell laufen ließ wie es konnte. Es ist die Linie mit exactScore.get().ExecutorService Future :: bekommen sehr langsam

Ich weiß nicht warum, aber es braucht manchmal mehr als 0,1 s, nur um den doppelten Wert des Future Object zu erhalten.

Warum ist das? Wie kann ich damit umgehen, dass es schneller läuft? Gibt es eine Möglichkeit, beim Multithreading direkt in die Double[] zu schreiben? Danke

int processors = Runtime.getRuntime().availableProcessors(); 
    ExecutorService service = Executors.newFixedThreadPool(processors); 

    // initialize output 
    Double[] presortedExScores = new Double[sortedHeuScores.length]; 

    for(int i =0; i < sortedHeuScores.length; i++){ 
     final int index = i; 
     final Collection<MolecularFormula> formulas_for_exact_method = multimap.get(sortedHeuScores[i]); 
     for (final MolecularFormula formula : formulas_for_exact_method){ 
      Future<Double> exactScore = service.submit(new Callable<Double>() { 
       @Override 
       public Double call() throws Exception { 
        return getScore(computeTreeExactly(computeGraph(formula))); 
       } 
      }); 
      presortedExScores[index] = exactScore.get(); 
     } 

    } 

Antwort

2

Das ist zu erwarten. Es ist dann nicht "langsamer"; es macht nur seine Arbeit.

Vom javadoc für get():

Waits bei Bedarf für die Berechnung abgeschlossen ist, und ruft dann das Ergebnis.

Lange Rede kurzer Sinn: Es scheint, dass Sie die Konzepte nicht verstehen, die Sie in Ihrem Code verwenden. Die Idee von Future ist, dass es Dinge in der Zukunft in der Zukunft tut.

Und get() rufen Sie auszudrücken: Ich kümmere mich nicht jetzt, bis die Ergebnisse dieser Berechnung warten „hinter“ die Zukunft verfügbar werden.

Also: Sie müssen zurücktreten und in Ihren Code erneut schauen; zu verstehen, wie deine verschiedenen "Threads of Activity" wirklich funktionieren; und wie/wann sie wieder zusammenkommen.

Eine Idee, die in den Sinn kommt: gerade jetzt, Sie Sie Ihre Future-Objekte in einer Schleife erstellen; und direkt nachdem du die Zukunft erstellt hast, rufst du get() an. Das widerspricht völlig der Idee, mehrere Futures zu erstellen. Mit anderen Worten: anstatt zu gehen:

foreach X 
    create future X.i 
    wait/get future X.i 

Sie so etwas wie

foreach X 
    create future X.i 

foreach X 
    wait/get for future X.i 

Mit anderen Worten tun könnte: lassen Sie Ihre Zukunft wirklich die Dinge tun, um parallel; anstelle der Durchsetzung sequentielle Verarbeitung.

Wenn das nicht "genug" hilft, dann wie gesagt: Sie müssen sich Ihr Gesamtdesign anschauen und feststellen, ob es Wege gibt, Dinge "auseinander zu ziehen". Im Moment geschieht jede Aktivität "eng" zusammen; und Überraschung: Wenn man viel Arbeit gleichzeitig macht, braucht es Zeit. Aber wie Sie sich vorstellen können: Ein solches Re-Design könnte eine Menge Arbeit sein; und ist nahezu unmöglich, ohne mehr über Ihr Problem/Ihre Codebasis zu erfahren.

Ein ausgefeilterer Ansatz wäre, dass Sie Code schreiben, wo jeder Future eine Art hat, "Ich bin erledigt" auszudrücken - dann würden Sie "nur" alle Futures starten; und warte, bis der letzte zurückkommt. Aber wie gesagt; Ich kann hier keine vollständige Lösung für Sie entwerfen.

Der andere wirklich wichtige Take-Away hier: Verwenden Sie nicht einfach blind Code, der "passiert" zu arbeiten.Eine Essenz der Programmierung ist zu verstehen jedes und Konzept in Ihrem Quellcode verwendet. Sie sollten eine ziemlich gute Idee haben, was Ihr Code macht vor läuft es und finden "oh, das get() macht die Dinge langsam".

+0

also wäre es besser wenn ich nicht versuche es schon in die for-schleife zu bekommen? Weil, wenn ich dich richtig verstehe, die anderen Executors keine Jobs bekommen werden, bis mein exactScor.get abgeschlossen ist (also keine neuen Multithreads in dieser Zeit). – user312549

+0

Bitte beachten Sie meine verschiedenen Updates. Es könnte helfen, Dinge in zwei Schleifen zu teilen; Aber das hängt wirklich von Dingen ab, die über eine einfache SO-Frage/Antwort-Diskussion hinausgehen. – GhostCat